mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-06 01:03:55 -06:00
target-arm queue:
* hw/arm/boot: fix direct kernel boot with initrd * hw/arm/msf2-som: Exit when the cpu is not the expected one * i.mx7: fix bugs in PCI controller needed to boot recent kernels * aspeed: add RTC device * aspeed: fix some timer device bugs * aspeed: add swift-bmc board * aspeed: vic: Add support for legacy register interface * aspeed: add aspeed-xdma device * Add new sbsa-ref board for aarch64 * target/arm: code refactoring in preparation for support of compilation with TCG disabled -----BEGIN PGP SIGNATURE----- iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAl0aNvIZHHBldGVyLm1h eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3uoEEACbv26LfzT5TIu1wlBaqSq5 CynAY3oJnrad6oH4KE0NiFxbgAvBGXj7mKX55uqJnrI6HY2ADVXbDE3rtVK7TG6O 4Swe7CCIOZV62/e5RmrWgqsCwxRsAsyLsQjmnL97WKgVTv/C33+iL6JgP+ApnK5D 4eYAitaxK6GB1+oIl6U6MgPROEOhoVGZ/U6Ejf7itL3dCcn8M5aMqOBn40WR5k/s rPM8tZASZuEV29qlmQZzatj0yETbjht2BOzO30/A5X9r3q9Lbwq6tP3RyTLE3KtL a2+nYobV8PP1WxjSZjAUMtwp8GiZvhB4jcaKpfN+CMIF+uhXVvy/idBHXzunclJ+ PZpuBozrSd3jFxmMzCZOddsy0y7MIuZWCw7fdCvYLkw4OSExYJkbTzUxE1jSA5Vb FbB983WvpYQXX5iT1Q1UGOqKnlgVfVC5eADBSCRGv4mqXOOf6xgoTgIEUgwdL1JN vKPsUQgogAJxELyddStj9aTrzHO50Qba8ahLLfIQWa0qFday+CckAqxjf5BROguc ak+jvdV8IoMSQYeZCUp8lmV7YCwbEozQ9cd+OGn4PdEKbPfSexiYFUWPxQgUg3EY Ul0e+sPXk4EZ1zMEU7752gKFTjZxwJ/0chVtxzjpqfA3cww5I0DR2SAlOCiYUmWq SRguMEJXOYaXjqaCIjrXVg== =bjIc -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20190701' into staging target-arm queue: * hw/arm/boot: fix direct kernel boot with initrd * hw/arm/msf2-som: Exit when the cpu is not the expected one * i.mx7: fix bugs in PCI controller needed to boot recent kernels * aspeed: add RTC device * aspeed: fix some timer device bugs * aspeed: add swift-bmc board * aspeed: vic: Add support for legacy register interface * aspeed: add aspeed-xdma device * Add new sbsa-ref board for aarch64 * target/arm: code refactoring in preparation for support of compilation with TCG disabled # gpg: Signature made Mon 01 Jul 2019 17:38:10 BST # 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-20190701: (46 commits) target/arm: Declare some M-profile functions publicly target/arm: Declare arm_log_exception() function publicly target/arm: Restrict PSCI to TCG target/arm/vfp_helper: Restrict the SoftFloat use to TCG target/arm/vfp_helper: Extract vfp_set_fpscr_from_host() target/arm/vfp_helper: Extract vfp_set_fpscr_to_host() target/arm/vfp_helper: Move code around target/arm: Move TLB related routines to tlb_helper.c target/arm: Declare get_phys_addr() function publicly target/arm: Move CPU state dumping routines to cpu.c target/arm: Move the DC ZVA helper into op_helper target/arm: Fix coding style issues target/arm: Fix multiline comment syntax target/arm/helper: Remove unused include target/arm: Add copyright boilerplate target/arm: Makefile cleanup (softmmu) target/arm: Makefile cleanup (KVM) target/arm: Makefile cleanup (ARM) target/arm: Makefile cleanup (Aarch64) hw/arm: Add arm SBSA reference machine, devices part ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
c4e42a9c2b
39 changed files with 2675 additions and 926 deletions
|
@ -184,6 +184,20 @@ config REALVIEW
|
|||
select DS1338 # I2C RTC+NVRAM
|
||||
select USB_OHCI
|
||||
|
||||
config SBSA_REF
|
||||
bool
|
||||
imply PCI_DEVICES
|
||||
select AHCI
|
||||
select ARM_SMMUV3
|
||||
select GPIO_KEY
|
||||
select PCI_EXPRESS
|
||||
select PCI_EXPRESS_GENERIC_BRIDGE
|
||||
select PFLASH_CFI01
|
||||
select PL011 # UART
|
||||
select PL031 # RTC
|
||||
select PL061 # GPIO
|
||||
select USB_EHCI_SYSBUS
|
||||
|
||||
config SABRELITE
|
||||
bool
|
||||
select FSL_IMX6
|
||||
|
|
|
@ -19,6 +19,7 @@ obj-$(CONFIG_SPITZ) += spitz.o
|
|||
obj-$(CONFIG_TOSA) += tosa.o
|
||||
obj-$(CONFIG_Z2) += z2.o
|
||||
obj-$(CONFIG_REALVIEW) += realview.o
|
||||
obj-$(CONFIG_SBSA_REF) += sbsa-ref.o
|
||||
obj-$(CONFIG_STELLARIS) += stellaris.o
|
||||
obj-$(CONFIG_COLLIE) += collie.o
|
||||
obj-$(CONFIG_VERSATILE) += versatilepb.o
|
||||
|
|
|
@ -22,17 +22,18 @@
|
|||
#include "hw/misc/tmp105.h"
|
||||
#include "qemu/log.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/loader.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/units.h"
|
||||
|
||||
static struct arm_boot_info aspeed_board_binfo = {
|
||||
.board_id = -1, /* device-tree-only board */
|
||||
.nb_cpus = 1,
|
||||
};
|
||||
|
||||
struct AspeedBoardState {
|
||||
AspeedSoCState soc;
|
||||
MemoryRegion ram_container;
|
||||
MemoryRegion ram;
|
||||
MemoryRegion max_ram;
|
||||
};
|
||||
|
@ -72,6 +73,17 @@ struct AspeedBoardState {
|
|||
SCU_AST2500_HW_STRAP_ACPI_ENABLE | \
|
||||
SCU_HW_STRAP_SPI_MODE(SCU_HW_STRAP_SPI_MASTER))
|
||||
|
||||
/* Swift hardware value: 0xF11AD206 */
|
||||
#define SWIFT_BMC_HW_STRAP1 ( \
|
||||
AST2500_HW_STRAP1_DEFAULTS | \
|
||||
SCU_AST2500_HW_STRAP_SPI_AUTOFETCH_ENABLE | \
|
||||
SCU_AST2500_HW_STRAP_GPIO_STRAP_ENABLE | \
|
||||
SCU_AST2500_HW_STRAP_UART_DEBUG | \
|
||||
SCU_AST2500_HW_STRAP_DDR4_ENABLE | \
|
||||
SCU_H_PLL_BYPASS_EN | \
|
||||
SCU_AST2500_HW_STRAP_ACPI_ENABLE | \
|
||||
SCU_HW_STRAP_SPI_MODE(SCU_HW_STRAP_SPI_MASTER))
|
||||
|
||||
/* Witherspoon hardware value: 0xF10AD216 (but use romulus definition) */
|
||||
#define WITHERSPOON_BMC_HW_STRAP1 ROMULUS_BMC_HW_STRAP1
|
||||
|
||||
|
@ -159,6 +171,10 @@ static void aspeed_board_init(MachineState *machine,
|
|||
ram_addr_t max_ram_size;
|
||||
|
||||
bmc = g_new0(AspeedBoardState, 1);
|
||||
|
||||
memory_region_init(&bmc->ram_container, NULL, "aspeed-ram-container",
|
||||
UINT32_MAX);
|
||||
|
||||
object_initialize_child(OBJECT(machine), "soc", &bmc->soc,
|
||||
(sizeof(bmc->soc)), cfg->soc_name, &error_abort,
|
||||
NULL);
|
||||
|
@ -171,6 +187,8 @@ static void aspeed_board_init(MachineState *machine,
|
|||
&error_abort);
|
||||
object_property_set_int(OBJECT(&bmc->soc), cfg->num_cs, "num-cs",
|
||||
&error_abort);
|
||||
object_property_set_int(OBJECT(&bmc->soc), smp_cpus, "num-cpus",
|
||||
&error_abort);
|
||||
if (machine->kernel_filename) {
|
||||
/*
|
||||
* When booting with a -kernel command line there is no u-boot
|
||||
|
@ -191,18 +209,16 @@ static void aspeed_board_init(MachineState *machine,
|
|||
&error_abort);
|
||||
|
||||
memory_region_allocate_system_memory(&bmc->ram, NULL, "ram", ram_size);
|
||||
memory_region_add_subregion(get_system_memory(), sc->info->sdram_base,
|
||||
&bmc->ram);
|
||||
object_property_add_const_link(OBJECT(&bmc->soc), "ram", OBJECT(&bmc->ram),
|
||||
&error_abort);
|
||||
memory_region_add_subregion(&bmc->ram_container, 0, &bmc->ram);
|
||||
memory_region_add_subregion(get_system_memory(),
|
||||
sc->info->memmap[ASPEED_SDRAM],
|
||||
&bmc->ram_container);
|
||||
|
||||
max_ram_size = object_property_get_uint(OBJECT(&bmc->soc), "max-ram-size",
|
||||
&error_abort);
|
||||
memory_region_init_io(&bmc->max_ram, NULL, &max_ram_ops, NULL,
|
||||
"max_ram", max_ram_size - ram_size);
|
||||
memory_region_add_subregion(get_system_memory(),
|
||||
sc->info->sdram_base + ram_size,
|
||||
&bmc->max_ram);
|
||||
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);
|
||||
|
@ -229,7 +245,8 @@ static void aspeed_board_init(MachineState *machine,
|
|||
aspeed_board_binfo.initrd_filename = machine->initrd_filename;
|
||||
aspeed_board_binfo.kernel_cmdline = machine->kernel_cmdline;
|
||||
aspeed_board_binfo.ram_size = ram_size;
|
||||
aspeed_board_binfo.loader_start = sc->info->sdram_base;
|
||||
aspeed_board_binfo.loader_start = sc->info->memmap[ASPEED_SDRAM];
|
||||
aspeed_board_binfo.nb_cpus = bmc->soc.num_cpus;
|
||||
|
||||
if (cfg->i2c_init) {
|
||||
cfg->i2c_init(bmc);
|
||||
|
@ -286,6 +303,35 @@ static void romulus_bmc_i2c_init(AspeedBoardState *bmc)
|
|||
i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 11), "ds1338", 0x32);
|
||||
}
|
||||
|
||||
static void swift_bmc_i2c_init(AspeedBoardState *bmc)
|
||||
{
|
||||
AspeedSoCState *soc = &bmc->soc;
|
||||
|
||||
i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 3), "pca9552", 0x60);
|
||||
|
||||
/* The swift board expects a TMP275 but a TMP105 is compatible */
|
||||
i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 7), "tmp105", 0x48);
|
||||
/* The swift board expects a pca9551 but a pca9552 is compatible */
|
||||
i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 7), "pca9552", 0x60);
|
||||
|
||||
/* The swift board expects an Epson RX8900 RTC but a ds1338 is compatible */
|
||||
i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 8), "ds1338", 0x32);
|
||||
i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 8), "pca9552", 0x60);
|
||||
|
||||
i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 9), "tmp423", 0x4c);
|
||||
/* The swift board expects a pca9539 but a pca9552 is compatible */
|
||||
i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 9), "pca9552", 0x74);
|
||||
|
||||
i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 10), "tmp423", 0x4c);
|
||||
/* The swift board expects a pca9539 but a pca9552 is compatible */
|
||||
i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 10), "pca9552",
|
||||
0x74);
|
||||
|
||||
/* The swift board expects a TMP275 but a TMP105 is compatible */
|
||||
i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 12), "tmp105", 0x48);
|
||||
i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 12), "tmp105", 0x4a);
|
||||
}
|
||||
|
||||
static void witherspoon_bmc_i2c_init(AspeedBoardState *bmc)
|
||||
{
|
||||
AspeedSoCState *soc = &bmc->soc;
|
||||
|
@ -326,7 +372,7 @@ static void aspeed_machine_class_init(ObjectClass *oc, void *data)
|
|||
|
||||
mc->desc = board->desc;
|
||||
mc->init = aspeed_machine_init;
|
||||
mc->max_cpus = 1;
|
||||
mc->max_cpus = ASPEED_CPUS_NUM;
|
||||
mc->no_sdcard = 1;
|
||||
mc->no_floppy = 1;
|
||||
mc->no_cdrom = 1;
|
||||
|
@ -376,6 +422,16 @@ static const AspeedBoardConfig aspeed_boards[] = {
|
|||
.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)",
|
||||
|
|
|
@ -19,36 +19,99 @@
|
|||
#include "hw/char/serial.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "hw/i2c/aspeed_i2c.h"
|
||||
#include "net/net.h"
|
||||
|
||||
#define ASPEED_SOC_UART_5_BASE 0x00184000
|
||||
#define ASPEED_SOC_IOMEM_SIZE 0x00200000
|
||||
#define ASPEED_SOC_IOMEM_BASE 0x1E600000
|
||||
#define ASPEED_SOC_FMC_BASE 0x1E620000
|
||||
#define ASPEED_SOC_SPI_BASE 0x1E630000
|
||||
#define ASPEED_SOC_SPI2_BASE 0x1E631000
|
||||
#define ASPEED_SOC_VIC_BASE 0x1E6C0000
|
||||
#define ASPEED_SOC_SDMC_BASE 0x1E6E0000
|
||||
#define ASPEED_SOC_SCU_BASE 0x1E6E2000
|
||||
#define ASPEED_SOC_SRAM_BASE 0x1E720000
|
||||
#define ASPEED_SOC_TIMER_BASE 0x1E782000
|
||||
#define ASPEED_SOC_WDT_BASE 0x1E785000
|
||||
#define ASPEED_SOC_I2C_BASE 0x1E78A000
|
||||
#define ASPEED_SOC_ETH1_BASE 0x1E660000
|
||||
#define ASPEED_SOC_ETH2_BASE 0x1E680000
|
||||
|
||||
static const int uart_irqs[] = { 9, 32, 33, 34, 10 };
|
||||
static const int timer_irqs[] = { 16, 17, 18, 35, 36, 37, 38, 39, };
|
||||
static const hwaddr aspeed_soc_ast2400_memmap[] = {
|
||||
[ASPEED_IOMEM] = 0x1E600000,
|
||||
[ASPEED_FMC] = 0x1E620000,
|
||||
[ASPEED_SPI1] = 0x1E630000,
|
||||
[ASPEED_VIC] = 0x1E6C0000,
|
||||
[ASPEED_SDMC] = 0x1E6E0000,
|
||||
[ASPEED_SCU] = 0x1E6E2000,
|
||||
[ASPEED_XDMA] = 0x1E6E7000,
|
||||
[ASPEED_ADC] = 0x1E6E9000,
|
||||
[ASPEED_SRAM] = 0x1E720000,
|
||||
[ASPEED_GPIO] = 0x1E780000,
|
||||
[ASPEED_RTC] = 0x1E781000,
|
||||
[ASPEED_TIMER1] = 0x1E782000,
|
||||
[ASPEED_WDT] = 0x1E785000,
|
||||
[ASPEED_PWM] = 0x1E786000,
|
||||
[ASPEED_LPC] = 0x1E789000,
|
||||
[ASPEED_IBT] = 0x1E789140,
|
||||
[ASPEED_I2C] = 0x1E78A000,
|
||||
[ASPEED_ETH1] = 0x1E660000,
|
||||
[ASPEED_ETH2] = 0x1E680000,
|
||||
[ASPEED_UART1] = 0x1E783000,
|
||||
[ASPEED_UART5] = 0x1E784000,
|
||||
[ASPEED_VUART] = 0x1E787000,
|
||||
[ASPEED_SDRAM] = 0x40000000,
|
||||
};
|
||||
|
||||
#define AST2400_SDRAM_BASE 0x40000000
|
||||
#define AST2500_SDRAM_BASE 0x80000000
|
||||
static const hwaddr aspeed_soc_ast2500_memmap[] = {
|
||||
[ASPEED_IOMEM] = 0x1E600000,
|
||||
[ASPEED_FMC] = 0x1E620000,
|
||||
[ASPEED_SPI1] = 0x1E630000,
|
||||
[ASPEED_SPI2] = 0x1E631000,
|
||||
[ASPEED_VIC] = 0x1E6C0000,
|
||||
[ASPEED_SDMC] = 0x1E6E0000,
|
||||
[ASPEED_SCU] = 0x1E6E2000,
|
||||
[ASPEED_XDMA] = 0x1E6E7000,
|
||||
[ASPEED_ADC] = 0x1E6E9000,
|
||||
[ASPEED_SRAM] = 0x1E720000,
|
||||
[ASPEED_GPIO] = 0x1E780000,
|
||||
[ASPEED_RTC] = 0x1E781000,
|
||||
[ASPEED_TIMER1] = 0x1E782000,
|
||||
[ASPEED_WDT] = 0x1E785000,
|
||||
[ASPEED_PWM] = 0x1E786000,
|
||||
[ASPEED_LPC] = 0x1E789000,
|
||||
[ASPEED_IBT] = 0x1E789140,
|
||||
[ASPEED_I2C] = 0x1E78A000,
|
||||
[ASPEED_ETH1] = 0x1E660000,
|
||||
[ASPEED_ETH2] = 0x1E680000,
|
||||
[ASPEED_UART1] = 0x1E783000,
|
||||
[ASPEED_UART5] = 0x1E784000,
|
||||
[ASPEED_VUART] = 0x1E787000,
|
||||
[ASPEED_SDRAM] = 0x80000000,
|
||||
};
|
||||
|
||||
static const int aspeed_soc_ast2400_irqmap[] = {
|
||||
[ASPEED_UART1] = 9,
|
||||
[ASPEED_UART2] = 32,
|
||||
[ASPEED_UART3] = 33,
|
||||
[ASPEED_UART4] = 34,
|
||||
[ASPEED_UART5] = 10,
|
||||
[ASPEED_VUART] = 8,
|
||||
[ASPEED_FMC] = 19,
|
||||
[ASPEED_SDMC] = 0,
|
||||
[ASPEED_SCU] = 21,
|
||||
[ASPEED_ADC] = 31,
|
||||
[ASPEED_GPIO] = 20,
|
||||
[ASPEED_RTC] = 22,
|
||||
[ASPEED_TIMER1] = 16,
|
||||
[ASPEED_TIMER2] = 17,
|
||||
[ASPEED_TIMER3] = 18,
|
||||
[ASPEED_TIMER4] = 35,
|
||||
[ASPEED_TIMER5] = 36,
|
||||
[ASPEED_TIMER6] = 37,
|
||||
[ASPEED_TIMER7] = 38,
|
||||
[ASPEED_TIMER8] = 39,
|
||||
[ASPEED_WDT] = 27,
|
||||
[ASPEED_PWM] = 28,
|
||||
[ASPEED_LPC] = 8,
|
||||
[ASPEED_IBT] = 8, /* LPC */
|
||||
[ASPEED_I2C] = 12,
|
||||
[ASPEED_ETH1] = 2,
|
||||
[ASPEED_ETH2] = 3,
|
||||
[ASPEED_XDMA] = 6,
|
||||
};
|
||||
|
||||
#define aspeed_soc_ast2500_irqmap aspeed_soc_ast2400_irqmap
|
||||
|
||||
static const hwaddr aspeed_soc_ast2400_spi_bases[] = { ASPEED_SOC_SPI_BASE };
|
||||
static const char *aspeed_soc_ast2400_typenames[] = { "aspeed.smc.spi" };
|
||||
|
||||
static const hwaddr aspeed_soc_ast2500_spi_bases[] = { ASPEED_SOC_SPI_BASE,
|
||||
ASPEED_SOC_SPI2_BASE};
|
||||
static const char *aspeed_soc_ast2500_typenames[] = {
|
||||
"aspeed.smc.ast2500-spi1", "aspeed.smc.ast2500-spi2" };
|
||||
|
||||
|
@ -57,57 +120,71 @@ static const AspeedSoCInfo aspeed_socs[] = {
|
|||
.name = "ast2400-a0",
|
||||
.cpu_type = ARM_CPU_TYPE_NAME("arm926"),
|
||||
.silicon_rev = AST2400_A0_SILICON_REV,
|
||||
.sdram_base = AST2400_SDRAM_BASE,
|
||||
.sram_size = 0x8000,
|
||||
.spis_num = 1,
|
||||
.spi_bases = aspeed_soc_ast2400_spi_bases,
|
||||
.fmc_typename = "aspeed.smc.fmc",
|
||||
.spi_typename = aspeed_soc_ast2400_typenames,
|
||||
.wdts_num = 2,
|
||||
.irqmap = aspeed_soc_ast2400_irqmap,
|
||||
.memmap = aspeed_soc_ast2400_memmap,
|
||||
.num_cpus = 1,
|
||||
}, {
|
||||
.name = "ast2400-a1",
|
||||
.cpu_type = ARM_CPU_TYPE_NAME("arm926"),
|
||||
.silicon_rev = AST2400_A1_SILICON_REV,
|
||||
.sdram_base = AST2400_SDRAM_BASE,
|
||||
.sram_size = 0x8000,
|
||||
.spis_num = 1,
|
||||
.spi_bases = aspeed_soc_ast2400_spi_bases,
|
||||
.fmc_typename = "aspeed.smc.fmc",
|
||||
.spi_typename = aspeed_soc_ast2400_typenames,
|
||||
.wdts_num = 2,
|
||||
.irqmap = aspeed_soc_ast2400_irqmap,
|
||||
.memmap = aspeed_soc_ast2400_memmap,
|
||||
.num_cpus = 1,
|
||||
}, {
|
||||
.name = "ast2400",
|
||||
.cpu_type = ARM_CPU_TYPE_NAME("arm926"),
|
||||
.silicon_rev = AST2400_A0_SILICON_REV,
|
||||
.sdram_base = AST2400_SDRAM_BASE,
|
||||
.sram_size = 0x8000,
|
||||
.spis_num = 1,
|
||||
.spi_bases = aspeed_soc_ast2400_spi_bases,
|
||||
.fmc_typename = "aspeed.smc.fmc",
|
||||
.spi_typename = aspeed_soc_ast2400_typenames,
|
||||
.wdts_num = 2,
|
||||
.irqmap = aspeed_soc_ast2400_irqmap,
|
||||
.memmap = aspeed_soc_ast2400_memmap,
|
||||
.num_cpus = 1,
|
||||
}, {
|
||||
.name = "ast2500-a1",
|
||||
.cpu_type = ARM_CPU_TYPE_NAME("arm1176"),
|
||||
.silicon_rev = AST2500_A1_SILICON_REV,
|
||||
.sdram_base = AST2500_SDRAM_BASE,
|
||||
.sram_size = 0x9000,
|
||||
.spis_num = 2,
|
||||
.spi_bases = aspeed_soc_ast2500_spi_bases,
|
||||
.fmc_typename = "aspeed.smc.ast2500-fmc",
|
||||
.spi_typename = aspeed_soc_ast2500_typenames,
|
||||
.wdts_num = 3,
|
||||
.irqmap = aspeed_soc_ast2500_irqmap,
|
||||
.memmap = aspeed_soc_ast2500_memmap,
|
||||
.num_cpus = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static qemu_irq aspeed_soc_get_irq(AspeedSoCState *s, int ctrl)
|
||||
{
|
||||
AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
|
||||
|
||||
return qdev_get_gpio_in(DEVICE(&s->vic), sc->info->irqmap[ctrl]);
|
||||
}
|
||||
|
||||
static void aspeed_soc_init(Object *obj)
|
||||
{
|
||||
AspeedSoCState *s = ASPEED_SOC(obj);
|
||||
AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
|
||||
int i;
|
||||
|
||||
object_initialize_child(obj, "cpu", OBJECT(&s->cpu), sizeof(s->cpu),
|
||||
sc->info->cpu_type, &error_abort, NULL);
|
||||
for (i = 0; i < sc->info->num_cpus; i++) {
|
||||
object_initialize_child(obj, "cpu[*]", OBJECT(&s->cpu[i]),
|
||||
sizeof(s->cpu[i]), sc->info->cpu_type,
|
||||
&error_abort, NULL);
|
||||
}
|
||||
|
||||
sysbus_init_child_obj(obj, "scu", OBJECT(&s->scu), sizeof(s->scu),
|
||||
TYPE_ASPEED_SCU);
|
||||
|
@ -123,6 +200,9 @@ static void aspeed_soc_init(Object *obj)
|
|||
sysbus_init_child_obj(obj, "vic", OBJECT(&s->vic), sizeof(s->vic),
|
||||
TYPE_ASPEED_VIC);
|
||||
|
||||
sysbus_init_child_obj(obj, "rtc", OBJECT(&s->rtc), sizeof(s->rtc),
|
||||
TYPE_ASPEED_RTC);
|
||||
|
||||
sysbus_init_child_obj(obj, "timerctrl", OBJECT(&s->timerctrl),
|
||||
sizeof(s->timerctrl), TYPE_ASPEED_TIMER);
|
||||
object_property_add_const_link(OBJECT(&s->timerctrl), "scu",
|
||||
|
@ -155,10 +235,17 @@ static void aspeed_soc_init(Object *obj)
|
|||
sizeof(s->wdt[i]), TYPE_ASPEED_WDT);
|
||||
qdev_prop_set_uint32(DEVICE(&s->wdt[i]), "silicon-rev",
|
||||
sc->info->silicon_rev);
|
||||
object_property_add_const_link(OBJECT(&s->wdt[i]), "scu",
|
||||
OBJECT(&s->scu), &error_abort);
|
||||
}
|
||||
|
||||
sysbus_init_child_obj(obj, "ftgmac100", OBJECT(&s->ftgmac100),
|
||||
sizeof(s->ftgmac100), TYPE_FTGMAC100);
|
||||
for (i = 0; i < ASPEED_MACS_NUM; i++) {
|
||||
sysbus_init_child_obj(obj, "ftgmac100[*]", OBJECT(&s->ftgmac100[i]),
|
||||
sizeof(s->ftgmac100[i]), TYPE_FTGMAC100);
|
||||
}
|
||||
|
||||
sysbus_init_child_obj(obj, "xdma", OBJECT(&s->xdma), sizeof(s->xdma),
|
||||
TYPE_ASPEED_XDMA);
|
||||
}
|
||||
|
||||
static void aspeed_soc_realize(DeviceState *dev, Error **errp)
|
||||
|
@ -169,14 +256,22 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
|
|||
Error *err = NULL, *local_err = NULL;
|
||||
|
||||
/* IO space */
|
||||
create_unimplemented_device("aspeed_soc.io",
|
||||
ASPEED_SOC_IOMEM_BASE, ASPEED_SOC_IOMEM_SIZE);
|
||||
create_unimplemented_device("aspeed_soc.io", sc->info->memmap[ASPEED_IOMEM],
|
||||
ASPEED_SOC_IOMEM_SIZE);
|
||||
|
||||
if (s->num_cpus > sc->info->num_cpus) {
|
||||
warn_report("%s: invalid number of CPUs %d, using default %d",
|
||||
sc->info->name, s->num_cpus, sc->info->num_cpus);
|
||||
s->num_cpus = sc->info->num_cpus;
|
||||
}
|
||||
|
||||
/* CPU */
|
||||
object_property_set_bool(OBJECT(&s->cpu), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
for (i = 0; i < s->num_cpus; i++) {
|
||||
object_property_set_bool(OBJECT(&s->cpu[i]), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* SRAM */
|
||||
|
@ -186,8 +281,8 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
|
|||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
memory_region_add_subregion(get_system_memory(), ASPEED_SOC_SRAM_BASE,
|
||||
&s->sram);
|
||||
memory_region_add_subregion(get_system_memory(),
|
||||
sc->info->memmap[ASPEED_SRAM], &s->sram);
|
||||
|
||||
/* SCU */
|
||||
object_property_set_bool(OBJECT(&s->scu), true, "realized", &err);
|
||||
|
@ -195,7 +290,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
|
|||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->scu), 0, ASPEED_SOC_SCU_BASE);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->scu), 0, sc->info->memmap[ASPEED_SCU]);
|
||||
|
||||
/* VIC */
|
||||
object_property_set_bool(OBJECT(&s->vic), true, "realized", &err);
|
||||
|
@ -203,29 +298,39 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
|
|||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->vic), 0, ASPEED_SOC_VIC_BASE);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->vic), 0, sc->info->memmap[ASPEED_VIC]);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->vic), 0,
|
||||
qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_IRQ));
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->vic), 1,
|
||||
qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_FIQ));
|
||||
|
||||
/* RTC */
|
||||
object_property_set_bool(OBJECT(&s->rtc), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->rtc), 0, sc->info->memmap[ASPEED_RTC]);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->rtc), 0,
|
||||
aspeed_soc_get_irq(s, ASPEED_RTC));
|
||||
|
||||
/* Timer */
|
||||
object_property_set_bool(OBJECT(&s->timerctrl), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->timerctrl), 0, ASPEED_SOC_TIMER_BASE);
|
||||
for (i = 0; i < ARRAY_SIZE(timer_irqs); i++) {
|
||||
qemu_irq irq = qdev_get_gpio_in(DEVICE(&s->vic), timer_irqs[i]);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->timerctrl), 0,
|
||||
sc->info->memmap[ASPEED_TIMER1]);
|
||||
for (i = 0; i < ASPEED_TIMER_NR_TIMERS; i++) {
|
||||
qemu_irq irq = aspeed_soc_get_irq(s, ASPEED_TIMER1 + i);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->timerctrl), i, irq);
|
||||
}
|
||||
|
||||
/* UART - attach an 8250 to the IO space as our UART5 */
|
||||
if (serial_hd(0)) {
|
||||
qemu_irq uart5 = qdev_get_gpio_in(DEVICE(&s->vic), uart_irqs[4]);
|
||||
serial_mm_init(get_system_memory(),
|
||||
ASPEED_SOC_IOMEM_BASE + ASPEED_SOC_UART_5_BASE, 2,
|
||||
qemu_irq uart5 = aspeed_soc_get_irq(s, ASPEED_UART5);
|
||||
serial_mm_init(get_system_memory(), sc->info->memmap[ASPEED_UART5], 2,
|
||||
uart5, 38400, serial_hd(0), DEVICE_LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
|
@ -235,21 +340,27 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
|
|||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c), 0, ASPEED_SOC_I2C_BASE);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c), 0, sc->info->memmap[ASPEED_I2C]);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c), 0,
|
||||
qdev_get_gpio_in(DEVICE(&s->vic), 12));
|
||||
aspeed_soc_get_irq(s, ASPEED_I2C));
|
||||
|
||||
/* FMC, The number of CS is set at the board level */
|
||||
object_property_set_int(OBJECT(&s->fmc), sc->info->memmap[ASPEED_SDRAM],
|
||||
"sdram-base", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
object_property_set_bool(OBJECT(&s->fmc), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 0, ASPEED_SOC_FMC_BASE);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 0, sc->info->memmap[ASPEED_FMC]);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 1,
|
||||
s->fmc.ctrl->flash_window_base);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->fmc), 0,
|
||||
qdev_get_gpio_in(DEVICE(&s->vic), 19));
|
||||
aspeed_soc_get_irq(s, ASPEED_FMC));
|
||||
|
||||
/* SPI */
|
||||
for (i = 0; i < sc->info->spis_num; i++) {
|
||||
|
@ -261,7 +372,8 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
|
|||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0, sc->info->spi_bases[i]);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0,
|
||||
sc->info->memmap[ASPEED_SPI1 + i]);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 1,
|
||||
s->spi[i].ctrl->flash_window_base);
|
||||
}
|
||||
|
@ -272,7 +384,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
|
|||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdmc), 0, ASPEED_SOC_SDMC_BASE);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdmc), 0, sc->info->memmap[ASPEED_SDMC]);
|
||||
|
||||
/* Watch dog */
|
||||
for (i = 0; i < sc->info->wdts_num; i++) {
|
||||
|
@ -282,23 +394,42 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
|
|||
return;
|
||||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[i]), 0,
|
||||
ASPEED_SOC_WDT_BASE + i * 0x20);
|
||||
sc->info->memmap[ASPEED_WDT] + i * 0x20);
|
||||
}
|
||||
|
||||
/* Net */
|
||||
qdev_set_nic_properties(DEVICE(&s->ftgmac100), &nd_table[0]);
|
||||
object_property_set_bool(OBJECT(&s->ftgmac100), true, "aspeed", &err);
|
||||
object_property_set_bool(OBJECT(&s->ftgmac100), true, "realized",
|
||||
&local_err);
|
||||
error_propagate(&err, local_err);
|
||||
for (i = 0; i < nb_nics; i++) {
|
||||
qdev_set_nic_properties(DEVICE(&s->ftgmac100[i]), &nd_table[i]);
|
||||
object_property_set_bool(OBJECT(&s->ftgmac100[i]), true, "aspeed",
|
||||
&err);
|
||||
object_property_set_bool(OBJECT(&s->ftgmac100[i]), true, "realized",
|
||||
&local_err);
|
||||
error_propagate(&err, local_err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->ftgmac100[i]), 0,
|
||||
sc->info->memmap[ASPEED_ETH1 + i]);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->ftgmac100[i]), 0,
|
||||
aspeed_soc_get_irq(s, ASPEED_ETH1 + i));
|
||||
}
|
||||
|
||||
/* XDMA */
|
||||
object_property_set_bool(OBJECT(&s->xdma), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->ftgmac100), 0, ASPEED_SOC_ETH1_BASE);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->ftgmac100), 0,
|
||||
qdev_get_gpio_in(DEVICE(&s->vic), 2));
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->xdma), 0,
|
||||
sc->info->memmap[ASPEED_XDMA]);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->xdma), 0,
|
||||
aspeed_soc_get_irq(s, ASPEED_XDMA));
|
||||
}
|
||||
static Property aspeed_soc_properties[] = {
|
||||
DEFINE_PROP_UINT32("num-cpus", AspeedSoCState, num_cpus, 0),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void aspeed_soc_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
|
@ -309,6 +440,7 @@ static void aspeed_soc_class_init(ObjectClass *oc, void *data)
|
|||
dc->realize = aspeed_soc_realize;
|
||||
/* Reason: Uses serial_hds and nd_table in realize() directly */
|
||||
dc->user_creatable = false;
|
||||
dc->props = aspeed_soc_properties;
|
||||
}
|
||||
|
||||
static const TypeInfo aspeed_soc_type_info = {
|
||||
|
|
|
@ -1109,10 +1109,11 @@ static void arm_setup_direct_kernel_boot(ARMCPU *cpu,
|
|||
info->initrd_filename);
|
||||
exit(1);
|
||||
}
|
||||
if (info->initrd_start + initrd_size > info->ram_size) {
|
||||
if (info->initrd_start + initrd_size > ram_end) {
|
||||
error_report("could not load initrd '%s': "
|
||||
"too big to fit into RAM after the kernel",
|
||||
info->initrd_filename);
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
initrd_size = 0;
|
||||
|
|
|
@ -526,6 +526,17 @@ static void fsl_imx7_realize(DeviceState *dev, Error **errp)
|
|||
*/
|
||||
create_unimplemented_device("lcdif", FSL_IMX7_LCDIF_ADDR,
|
||||
FSL_IMX7_LCDIF_SIZE);
|
||||
|
||||
/*
|
||||
* DMA APBH
|
||||
*/
|
||||
create_unimplemented_device("dma-apbh", FSL_IMX7_DMA_APBH_ADDR,
|
||||
FSL_IMX7_DMA_APBH_SIZE);
|
||||
/*
|
||||
* PCIe PHY
|
||||
*/
|
||||
create_unimplemented_device("pcie-phy", FSL_IMX7_PCIE_PHY_ADDR,
|
||||
FSL_IMX7_PCIE_PHY_SIZE);
|
||||
}
|
||||
|
||||
static void fsl_imx7_class_init(ObjectClass *oc, void *data)
|
||||
|
|
|
@ -53,6 +53,7 @@ static void emcraft_sf2_s2s010_init(MachineState *machine)
|
|||
if (strcmp(machine->cpu_type, mc->default_cpu_type) != 0) {
|
||||
error_report("This board can only be used with CPU %s",
|
||||
mc->default_cpu_type);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memory_region_init_ram(ddr, NULL, "ddr-ram", DDR_SIZE,
|
||||
|
|
806
hw/arm/sbsa-ref.c
Normal file
806
hw/arm/sbsa-ref.c
Normal file
|
@ -0,0 +1,806 @@
|
|||
/*
|
||||
* ARM SBSA Reference Platform emulation
|
||||
*
|
||||
* Copyright (c) 2018 Linaro Limited
|
||||
* Written by Hongbo Zhang <hongbo.zhang@linaro.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2 or later, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/units.h"
|
||||
#include "sysemu/device_tree.h"
|
||||
#include "sysemu/numa.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "exec/hwaddr.h"
|
||||
#include "kvm_arm.h"
|
||||
#include "hw/arm/boot.h"
|
||||
#include "hw/block/flash.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/ide/internal.h"
|
||||
#include "hw/ide/ahci_internal.h"
|
||||
#include "hw/intc/arm_gicv3_common.h"
|
||||
#include "hw/loader.h"
|
||||
#include "hw/pci-host/gpex.h"
|
||||
#include "hw/usb.h"
|
||||
#include "net/net.h"
|
||||
|
||||
#define RAMLIMIT_GB 8192
|
||||
#define RAMLIMIT_BYTES (RAMLIMIT_GB * GiB)
|
||||
|
||||
#define NUM_IRQS 256
|
||||
#define NUM_SMMU_IRQS 4
|
||||
#define NUM_SATA_PORTS 6
|
||||
|
||||
#define VIRTUAL_PMU_IRQ 7
|
||||
#define ARCH_GIC_MAINT_IRQ 9
|
||||
#define ARCH_TIMER_VIRT_IRQ 11
|
||||
#define ARCH_TIMER_S_EL1_IRQ 13
|
||||
#define ARCH_TIMER_NS_EL1_IRQ 14
|
||||
#define ARCH_TIMER_NS_EL2_IRQ 10
|
||||
|
||||
enum {
|
||||
SBSA_FLASH,
|
||||
SBSA_MEM,
|
||||
SBSA_CPUPERIPHS,
|
||||
SBSA_GIC_DIST,
|
||||
SBSA_GIC_REDIST,
|
||||
SBSA_SMMU,
|
||||
SBSA_UART,
|
||||
SBSA_RTC,
|
||||
SBSA_PCIE,
|
||||
SBSA_PCIE_MMIO,
|
||||
SBSA_PCIE_MMIO_HIGH,
|
||||
SBSA_PCIE_PIO,
|
||||
SBSA_PCIE_ECAM,
|
||||
SBSA_GPIO,
|
||||
SBSA_SECURE_UART,
|
||||
SBSA_SECURE_UART_MM,
|
||||
SBSA_SECURE_MEM,
|
||||
SBSA_AHCI,
|
||||
SBSA_EHCI,
|
||||
};
|
||||
|
||||
typedef struct MemMapEntry {
|
||||
hwaddr base;
|
||||
hwaddr size;
|
||||
} MemMapEntry;
|
||||
|
||||
typedef struct {
|
||||
MachineState parent;
|
||||
struct arm_boot_info bootinfo;
|
||||
int smp_cpus;
|
||||
void *fdt;
|
||||
int fdt_size;
|
||||
int psci_conduit;
|
||||
PFlashCFI01 *flash[2];
|
||||
} SBSAMachineState;
|
||||
|
||||
#define TYPE_SBSA_MACHINE MACHINE_TYPE_NAME("sbsa-ref")
|
||||
#define SBSA_MACHINE(obj) \
|
||||
OBJECT_CHECK(SBSAMachineState, (obj), TYPE_SBSA_MACHINE)
|
||||
|
||||
static const MemMapEntry sbsa_ref_memmap[] = {
|
||||
/* 512M boot ROM */
|
||||
[SBSA_FLASH] = { 0, 0x20000000 },
|
||||
/* 512M secure memory */
|
||||
[SBSA_SECURE_MEM] = { 0x20000000, 0x20000000 },
|
||||
/* Space reserved for CPU peripheral devices */
|
||||
[SBSA_CPUPERIPHS] = { 0x40000000, 0x00040000 },
|
||||
[SBSA_GIC_DIST] = { 0x40060000, 0x00010000 },
|
||||
[SBSA_GIC_REDIST] = { 0x40080000, 0x04000000 },
|
||||
[SBSA_UART] = { 0x60000000, 0x00001000 },
|
||||
[SBSA_RTC] = { 0x60010000, 0x00001000 },
|
||||
[SBSA_GPIO] = { 0x60020000, 0x00001000 },
|
||||
[SBSA_SECURE_UART] = { 0x60030000, 0x00001000 },
|
||||
[SBSA_SECURE_UART_MM] = { 0x60040000, 0x00001000 },
|
||||
[SBSA_SMMU] = { 0x60050000, 0x00020000 },
|
||||
/* Space here reserved for more SMMUs */
|
||||
[SBSA_AHCI] = { 0x60100000, 0x00010000 },
|
||||
[SBSA_EHCI] = { 0x60110000, 0x00010000 },
|
||||
/* Space here reserved for other devices */
|
||||
[SBSA_PCIE_PIO] = { 0x7fff0000, 0x00010000 },
|
||||
/* 32-bit address PCIE MMIO space */
|
||||
[SBSA_PCIE_MMIO] = { 0x80000000, 0x70000000 },
|
||||
/* 256M PCIE ECAM space */
|
||||
[SBSA_PCIE_ECAM] = { 0xf0000000, 0x10000000 },
|
||||
/* ~1TB PCIE MMIO space (4GB to 1024GB boundary) */
|
||||
[SBSA_PCIE_MMIO_HIGH] = { 0x100000000ULL, 0xFF00000000ULL },
|
||||
[SBSA_MEM] = { 0x10000000000ULL, RAMLIMIT_BYTES },
|
||||
};
|
||||
|
||||
static const int sbsa_ref_irqmap[] = {
|
||||
[SBSA_UART] = 1,
|
||||
[SBSA_RTC] = 2,
|
||||
[SBSA_PCIE] = 3, /* ... to 6 */
|
||||
[SBSA_GPIO] = 7,
|
||||
[SBSA_SECURE_UART] = 8,
|
||||
[SBSA_SECURE_UART_MM] = 9,
|
||||
[SBSA_AHCI] = 10,
|
||||
[SBSA_EHCI] = 11,
|
||||
};
|
||||
|
||||
/*
|
||||
* Firmware on this machine only uses ACPI table to load OS, these limited
|
||||
* device tree nodes are just to let firmware know the info which varies from
|
||||
* command line parameters, so it is not necessary to be fully compatible
|
||||
* with the kernel CPU and NUMA binding rules.
|
||||
*/
|
||||
static void create_fdt(SBSAMachineState *sms)
|
||||
{
|
||||
void *fdt = create_device_tree(&sms->fdt_size);
|
||||
const MachineState *ms = MACHINE(sms);
|
||||
int cpu;
|
||||
|
||||
if (!fdt) {
|
||||
error_report("create_device_tree() failed");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
sms->fdt = fdt;
|
||||
|
||||
qemu_fdt_setprop_string(fdt, "/", "compatible", "linux,sbsa-ref");
|
||||
qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 0x2);
|
||||
qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 0x2);
|
||||
|
||||
if (have_numa_distance) {
|
||||
int size = nb_numa_nodes * nb_numa_nodes * 3 * sizeof(uint32_t);
|
||||
uint32_t *matrix = g_malloc0(size);
|
||||
int idx, i, j;
|
||||
|
||||
for (i = 0; i < nb_numa_nodes; i++) {
|
||||
for (j = 0; j < nb_numa_nodes; j++) {
|
||||
idx = (i * nb_numa_nodes + j) * 3;
|
||||
matrix[idx + 0] = cpu_to_be32(i);
|
||||
matrix[idx + 1] = cpu_to_be32(j);
|
||||
matrix[idx + 2] = cpu_to_be32(numa_info[i].distance[j]);
|
||||
}
|
||||
}
|
||||
|
||||
qemu_fdt_add_subnode(fdt, "/distance-map");
|
||||
qemu_fdt_setprop(fdt, "/distance-map", "distance-matrix",
|
||||
matrix, size);
|
||||
g_free(matrix);
|
||||
}
|
||||
|
||||
qemu_fdt_add_subnode(sms->fdt, "/cpus");
|
||||
|
||||
for (cpu = sms->smp_cpus - 1; cpu >= 0; cpu--) {
|
||||
char *nodename = g_strdup_printf("/cpus/cpu@%d", cpu);
|
||||
ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(cpu));
|
||||
CPUState *cs = CPU(armcpu);
|
||||
|
||||
qemu_fdt_add_subnode(sms->fdt, nodename);
|
||||
|
||||
if (ms->possible_cpus->cpus[cs->cpu_index].props.has_node_id) {
|
||||
qemu_fdt_setprop_cell(sms->fdt, nodename, "numa-node-id",
|
||||
ms->possible_cpus->cpus[cs->cpu_index].props.node_id);
|
||||
}
|
||||
|
||||
g_free(nodename);
|
||||
}
|
||||
}
|
||||
|
||||
#define SBSA_FLASH_SECTOR_SIZE (256 * KiB)
|
||||
|
||||
static PFlashCFI01 *sbsa_flash_create1(SBSAMachineState *sms,
|
||||
const char *name,
|
||||
const char *alias_prop_name)
|
||||
{
|
||||
/*
|
||||
* Create a single flash device. We use the same parameters as
|
||||
* the flash devices on the Versatile Express board.
|
||||
*/
|
||||
DeviceState *dev = qdev_create(NULL, TYPE_PFLASH_CFI01);
|
||||
|
||||
qdev_prop_set_uint64(dev, "sector-length", SBSA_FLASH_SECTOR_SIZE);
|
||||
qdev_prop_set_uint8(dev, "width", 4);
|
||||
qdev_prop_set_uint8(dev, "device-width", 2);
|
||||
qdev_prop_set_bit(dev, "big-endian", false);
|
||||
qdev_prop_set_uint16(dev, "id0", 0x89);
|
||||
qdev_prop_set_uint16(dev, "id1", 0x18);
|
||||
qdev_prop_set_uint16(dev, "id2", 0x00);
|
||||
qdev_prop_set_uint16(dev, "id3", 0x00);
|
||||
qdev_prop_set_string(dev, "name", name);
|
||||
object_property_add_child(OBJECT(sms), name, OBJECT(dev),
|
||||
&error_abort);
|
||||
object_property_add_alias(OBJECT(sms), alias_prop_name,
|
||||
OBJECT(dev), "drive", &error_abort);
|
||||
return PFLASH_CFI01(dev);
|
||||
}
|
||||
|
||||
static void sbsa_flash_create(SBSAMachineState *sms)
|
||||
{
|
||||
sms->flash[0] = sbsa_flash_create1(sms, "sbsa.flash0", "pflash0");
|
||||
sms->flash[1] = sbsa_flash_create1(sms, "sbsa.flash1", "pflash1");
|
||||
}
|
||||
|
||||
static void sbsa_flash_map1(PFlashCFI01 *flash,
|
||||
hwaddr base, hwaddr size,
|
||||
MemoryRegion *sysmem)
|
||||
{
|
||||
DeviceState *dev = DEVICE(flash);
|
||||
|
||||
assert(size % SBSA_FLASH_SECTOR_SIZE == 0);
|
||||
assert(size / SBSA_FLASH_SECTOR_SIZE <= UINT32_MAX);
|
||||
qdev_prop_set_uint32(dev, "num-blocks", size / SBSA_FLASH_SECTOR_SIZE);
|
||||
qdev_init_nofail(dev);
|
||||
|
||||
memory_region_add_subregion(sysmem, base,
|
||||
sysbus_mmio_get_region(SYS_BUS_DEVICE(dev),
|
||||
0));
|
||||
}
|
||||
|
||||
static void sbsa_flash_map(SBSAMachineState *sms,
|
||||
MemoryRegion *sysmem,
|
||||
MemoryRegion *secure_sysmem)
|
||||
{
|
||||
/*
|
||||
* Map two flash devices to fill the SBSA_FLASH space in the memmap.
|
||||
* sysmem is the system memory space. secure_sysmem is the secure view
|
||||
* of the system, and the first flash device should be made visible only
|
||||
* there. The second flash device is visible to both secure and nonsecure.
|
||||
* If sysmem == secure_sysmem this means there is no separate Secure
|
||||
* address space and both flash devices are generally visible.
|
||||
*/
|
||||
hwaddr flashsize = sbsa_ref_memmap[SBSA_FLASH].size / 2;
|
||||
hwaddr flashbase = sbsa_ref_memmap[SBSA_FLASH].base;
|
||||
|
||||
sbsa_flash_map1(sms->flash[0], flashbase, flashsize,
|
||||
secure_sysmem);
|
||||
sbsa_flash_map1(sms->flash[1], flashbase + flashsize, flashsize,
|
||||
sysmem);
|
||||
}
|
||||
|
||||
static bool sbsa_firmware_init(SBSAMachineState *sms,
|
||||
MemoryRegion *sysmem,
|
||||
MemoryRegion *secure_sysmem)
|
||||
{
|
||||
int i;
|
||||
BlockBackend *pflash_blk0;
|
||||
|
||||
/* Map legacy -drive if=pflash to machine properties */
|
||||
for (i = 0; i < ARRAY_SIZE(sms->flash); i++) {
|
||||
pflash_cfi01_legacy_drive(sms->flash[i],
|
||||
drive_get(IF_PFLASH, 0, i));
|
||||
}
|
||||
|
||||
sbsa_flash_map(sms, sysmem, secure_sysmem);
|
||||
|
||||
pflash_blk0 = pflash_cfi01_get_blk(sms->flash[0]);
|
||||
|
||||
if (bios_name) {
|
||||
char *fname;
|
||||
MemoryRegion *mr;
|
||||
int image_size;
|
||||
|
||||
if (pflash_blk0) {
|
||||
error_report("The contents of the first flash device may be "
|
||||
"specified with -bios or with -drive if=pflash... "
|
||||
"but you cannot use both options at once");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Fall back to -bios */
|
||||
|
||||
fname = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
|
||||
if (!fname) {
|
||||
error_report("Could not find ROM image '%s'", bios_name);
|
||||
exit(1);
|
||||
}
|
||||
mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(sms->flash[0]), 0);
|
||||
image_size = load_image_mr(fname, mr);
|
||||
g_free(fname);
|
||||
if (image_size < 0) {
|
||||
error_report("Could not load ROM image '%s'", bios_name);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
return pflash_blk0 || bios_name;
|
||||
}
|
||||
|
||||
static void create_secure_ram(SBSAMachineState *sms,
|
||||
MemoryRegion *secure_sysmem)
|
||||
{
|
||||
MemoryRegion *secram = g_new(MemoryRegion, 1);
|
||||
hwaddr base = sbsa_ref_memmap[SBSA_SECURE_MEM].base;
|
||||
hwaddr size = sbsa_ref_memmap[SBSA_SECURE_MEM].size;
|
||||
|
||||
memory_region_init_ram(secram, NULL, "sbsa-ref.secure-ram", size,
|
||||
&error_fatal);
|
||||
memory_region_add_subregion(secure_sysmem, base, secram);
|
||||
}
|
||||
|
||||
static void create_gic(SBSAMachineState *sms, qemu_irq *pic)
|
||||
{
|
||||
DeviceState *gicdev;
|
||||
SysBusDevice *gicbusdev;
|
||||
const char *gictype;
|
||||
uint32_t redist0_capacity, redist0_count;
|
||||
int i;
|
||||
|
||||
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);
|
||||
/*
|
||||
* 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);
|
||||
|
||||
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_init_nofail(gicdev);
|
||||
gicbusdev = SYS_BUS_DEVICE(gicdev);
|
||||
sysbus_mmio_map(gicbusdev, 0, sbsa_ref_memmap[SBSA_GIC_DIST].base);
|
||||
sysbus_mmio_map(gicbusdev, 1, sbsa_ref_memmap[SBSA_GIC_REDIST].base);
|
||||
|
||||
/*
|
||||
* Wire the outputs from each CPU's generic timer and the GICv3
|
||||
* maintenance interrupt signal to the appropriate GIC PPI inputs,
|
||||
* and the GIC's IRQ/FIQ/VIRQ/VFIQ interrupt outputs to the CPU's inputs.
|
||||
*/
|
||||
for (i = 0; i < smp_cpus; i++) {
|
||||
DeviceState *cpudev = DEVICE(qemu_get_cpu(i));
|
||||
int ppibase = NUM_IRQS + i * GIC_INTERNAL + GIC_NR_SGIS;
|
||||
int irq;
|
||||
/*
|
||||
* Mapping from the output timer irq lines from the CPU to the
|
||||
* GIC PPI inputs used for this board.
|
||||
*/
|
||||
const int timer_irq[] = {
|
||||
[GTIMER_PHYS] = ARCH_TIMER_NS_EL1_IRQ,
|
||||
[GTIMER_VIRT] = ARCH_TIMER_VIRT_IRQ,
|
||||
[GTIMER_HYP] = ARCH_TIMER_NS_EL2_IRQ,
|
||||
[GTIMER_SEC] = ARCH_TIMER_S_EL1_IRQ,
|
||||
};
|
||||
|
||||
for (irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) {
|
||||
qdev_connect_gpio_out(cpudev, irq,
|
||||
qdev_get_gpio_in(gicdev,
|
||||
ppibase + timer_irq[irq]));
|
||||
}
|
||||
|
||||
qdev_connect_gpio_out_named(cpudev, "gicv3-maintenance-interrupt", 0,
|
||||
qdev_get_gpio_in(gicdev, ppibase
|
||||
+ ARCH_GIC_MAINT_IRQ));
|
||||
qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0,
|
||||
qdev_get_gpio_in(gicdev, ppibase
|
||||
+ VIRTUAL_PMU_IRQ));
|
||||
|
||||
sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
|
||||
sysbus_connect_irq(gicbusdev, i + smp_cpus,
|
||||
qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
|
||||
sysbus_connect_irq(gicbusdev, i + 2 * smp_cpus,
|
||||
qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ));
|
||||
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,
|
||||
MemoryRegion *mem, Chardev *chr)
|
||||
{
|
||||
hwaddr base = sbsa_ref_memmap[uart].base;
|
||||
int irq = sbsa_ref_irqmap[uart];
|
||||
DeviceState *dev = qdev_create(NULL, "pl011");
|
||||
SysBusDevice *s = SYS_BUS_DEVICE(dev);
|
||||
|
||||
qdev_prop_set_chr(dev, "chardev", chr);
|
||||
qdev_init_nofail(dev);
|
||||
memory_region_add_subregion(mem, base,
|
||||
sysbus_mmio_get_region(s, 0));
|
||||
sysbus_connect_irq(s, 0, pic[irq]);
|
||||
}
|
||||
|
||||
static void create_rtc(const SBSAMachineState *sms, qemu_irq *pic)
|
||||
{
|
||||
hwaddr base = sbsa_ref_memmap[SBSA_RTC].base;
|
||||
int irq = sbsa_ref_irqmap[SBSA_RTC];
|
||||
|
||||
sysbus_create_simple("pl031", base, pic[irq]);
|
||||
}
|
||||
|
||||
static DeviceState *gpio_key_dev;
|
||||
static void sbsa_ref_powerdown_req(Notifier *n, void *opaque)
|
||||
{
|
||||
/* use gpio Pin 3 for power button event */
|
||||
qemu_set_irq(qdev_get_gpio_in(gpio_key_dev, 0), 1);
|
||||
}
|
||||
|
||||
static Notifier sbsa_ref_powerdown_notifier = {
|
||||
.notify = sbsa_ref_powerdown_req
|
||||
};
|
||||
|
||||
static void create_gpio(const SBSAMachineState *sms, qemu_irq *pic)
|
||||
{
|
||||
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]);
|
||||
|
||||
gpio_key_dev = sysbus_create_simple("gpio-key", -1,
|
||||
qdev_get_gpio_in(pl061_dev, 3));
|
||||
|
||||
/* connect powerdown request */
|
||||
qemu_register_powerdown_notifier(&sbsa_ref_powerdown_notifier);
|
||||
}
|
||||
|
||||
static void create_ahci(const SBSAMachineState *sms, qemu_irq *pic)
|
||||
{
|
||||
hwaddr base = sbsa_ref_memmap[SBSA_AHCI].base;
|
||||
int irq = sbsa_ref_irqmap[SBSA_AHCI];
|
||||
DeviceState *dev;
|
||||
DriveInfo *hd[NUM_SATA_PORTS];
|
||||
SysbusAHCIState *sysahci;
|
||||
AHCIState *ahci;
|
||||
int i;
|
||||
|
||||
dev = qdev_create(NULL, "sysbus-ahci");
|
||||
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]);
|
||||
|
||||
sysahci = SYSBUS_AHCI(dev);
|
||||
ahci = &sysahci->ahci;
|
||||
ide_drive_get(hd, ARRAY_SIZE(hd));
|
||||
for (i = 0; i < ahci->ports; i++) {
|
||||
if (hd[i] == NULL) {
|
||||
continue;
|
||||
}
|
||||
ide_create_drive(&ahci->dev[i].port, 0, hd[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void create_ehci(const SBSAMachineState *sms, qemu_irq *pic)
|
||||
{
|
||||
hwaddr base = sbsa_ref_memmap[SBSA_EHCI].base;
|
||||
int irq = sbsa_ref_irqmap[SBSA_EHCI];
|
||||
|
||||
sysbus_create_simple("platform-ehci-usb", base, pic[irq]);
|
||||
}
|
||||
|
||||
static void create_smmu(const SBSAMachineState *sms, qemu_irq *pic,
|
||||
PCIBus *bus)
|
||||
{
|
||||
hwaddr base = sbsa_ref_memmap[SBSA_SMMU].base;
|
||||
int irq = sbsa_ref_irqmap[SBSA_SMMU];
|
||||
DeviceState *dev;
|
||||
int i;
|
||||
|
||||
dev = qdev_create(NULL, "arm-smmuv3");
|
||||
|
||||
object_property_set_link(OBJECT(dev), OBJECT(bus), "primary-bus",
|
||||
&error_abort);
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
||||
static void create_pcie(SBSAMachineState *sms, qemu_irq *pic)
|
||||
{
|
||||
hwaddr base_ecam = sbsa_ref_memmap[SBSA_PCIE_ECAM].base;
|
||||
hwaddr size_ecam = sbsa_ref_memmap[SBSA_PCIE_ECAM].size;
|
||||
hwaddr base_mmio = sbsa_ref_memmap[SBSA_PCIE_MMIO].base;
|
||||
hwaddr size_mmio = sbsa_ref_memmap[SBSA_PCIE_MMIO].size;
|
||||
hwaddr base_mmio_high = sbsa_ref_memmap[SBSA_PCIE_MMIO_HIGH].base;
|
||||
hwaddr size_mmio_high = sbsa_ref_memmap[SBSA_PCIE_MMIO_HIGH].size;
|
||||
hwaddr base_pio = sbsa_ref_memmap[SBSA_PCIE_PIO].base;
|
||||
int irq = sbsa_ref_irqmap[SBSA_PCIE];
|
||||
MemoryRegion *mmio_alias, *mmio_alias_high, *mmio_reg;
|
||||
MemoryRegion *ecam_alias, *ecam_reg;
|
||||
DeviceState *dev;
|
||||
PCIHostState *pci;
|
||||
int i;
|
||||
|
||||
dev = qdev_create(NULL, TYPE_GPEX_HOST);
|
||||
qdev_init_nofail(dev);
|
||||
|
||||
/* Map ECAM space */
|
||||
ecam_alias = g_new0(MemoryRegion, 1);
|
||||
ecam_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
|
||||
memory_region_init_alias(ecam_alias, OBJECT(dev), "pcie-ecam",
|
||||
ecam_reg, 0, size_ecam);
|
||||
memory_region_add_subregion(get_system_memory(), base_ecam, ecam_alias);
|
||||
|
||||
/* Map the MMIO space */
|
||||
mmio_alias = g_new0(MemoryRegion, 1);
|
||||
mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
|
||||
memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio",
|
||||
mmio_reg, base_mmio, size_mmio);
|
||||
memory_region_add_subregion(get_system_memory(), base_mmio, mmio_alias);
|
||||
|
||||
/* Map the MMIO_HIGH space */
|
||||
mmio_alias_high = g_new0(MemoryRegion, 1);
|
||||
memory_region_init_alias(mmio_alias_high, OBJECT(dev), "pcie-mmio-high",
|
||||
mmio_reg, base_mmio_high, size_mmio_high);
|
||||
memory_region_add_subregion(get_system_memory(), base_mmio_high,
|
||||
mmio_alias_high);
|
||||
|
||||
/* Map IO port space */
|
||||
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]);
|
||||
gpex_set_irq_num(GPEX_HOST(dev), i, irq + i);
|
||||
}
|
||||
|
||||
pci = PCI_HOST_BRIDGE(dev);
|
||||
if (pci->bus) {
|
||||
for (i = 0; i < nb_nics; i++) {
|
||||
NICInfo *nd = &nd_table[i];
|
||||
|
||||
if (!nd->model) {
|
||||
nd->model = g_strdup("e1000e");
|
||||
}
|
||||
|
||||
pci_nic_init_nofail(nd, pci->bus, nd->model, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
pci_create_simple(pci->bus, -1, "VGA");
|
||||
|
||||
create_smmu(sms, pic, pci->bus);
|
||||
}
|
||||
|
||||
static void *sbsa_ref_dtb(const struct arm_boot_info *binfo, int *fdt_size)
|
||||
{
|
||||
const SBSAMachineState *board = container_of(binfo, SBSAMachineState,
|
||||
bootinfo);
|
||||
|
||||
*fdt_size = board->fdt_size;
|
||||
return board->fdt;
|
||||
}
|
||||
|
||||
static void sbsa_ref_init(MachineState *machine)
|
||||
{
|
||||
SBSAMachineState *sms = SBSA_MACHINE(machine);
|
||||
MachineClass *mc = MACHINE_GET_CLASS(machine);
|
||||
MemoryRegion *sysmem = get_system_memory();
|
||||
MemoryRegion *secure_sysmem = NULL;
|
||||
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
||||
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 "
|
||||
"cortex-a57 not supported");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (kvm_enabled()) {
|
||||
error_report("sbsa-ref: KVM is not supported for this machine");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* The Secure view of the world is the same as the NonSecure,
|
||||
* but with a few extra devices. Create it as a container region
|
||||
* containing the system memory at low priority; any secure-only
|
||||
* devices go in at higher priority and take precedence.
|
||||
*/
|
||||
secure_sysmem = g_new(MemoryRegion, 1);
|
||||
memory_region_init(secure_sysmem, OBJECT(machine), "secure-memory",
|
||||
UINT64_MAX);
|
||||
memory_region_add_subregion_overlap(secure_sysmem, 0, sysmem, -1);
|
||||
|
||||
firmware_loaded = sbsa_firmware_init(sms, sysmem,
|
||||
secure_sysmem ?: sysmem);
|
||||
|
||||
if (machine->kernel_filename && firmware_loaded) {
|
||||
error_report("sbsa-ref: No fw_cfg device on this machine, "
|
||||
"so -kernel option is not supported when firmware loaded, "
|
||||
"please load OS from hard disk instead");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* This machine has EL3 enabled, external firmware should supply PSCI
|
||||
* implementation, so the QEMU's internal PSCI is disabled.
|
||||
*/
|
||||
sms->psci_conduit = QEMU_PSCI_CONDUIT_DISABLED;
|
||||
|
||||
sbsa_max_cpus = sbsa_ref_memmap[SBSA_GIC_REDIST].size / GICV3_REDIST_SIZE;
|
||||
|
||||
if (max_cpus > sbsa_max_cpus) {
|
||||
error_report("Number of SMP CPUs requested (%d) exceeds max CPUs "
|
||||
"supported by machine 'sbsa-ref' (%d)",
|
||||
max_cpus, sbsa_max_cpus);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
sms->smp_cpus = smp_cpus;
|
||||
|
||||
if (machine->ram_size > sbsa_ref_memmap[SBSA_MEM].size) {
|
||||
error_report("sbsa-ref: cannot model more than %dGB RAM", RAMLIMIT_GB);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
possible_cpus = mc->possible_cpu_arch_ids(machine);
|
||||
for (n = 0; n < possible_cpus->len; n++) {
|
||||
Object *cpuobj;
|
||||
CPUState *cs;
|
||||
|
||||
if (n >= smp_cpus) {
|
||||
break;
|
||||
}
|
||||
|
||||
cpuobj = object_new(possible_cpus->cpus[n].type);
|
||||
object_property_set_int(cpuobj, possible_cpus->cpus[n].arch_id,
|
||||
"mp-affinity", NULL);
|
||||
|
||||
cs = CPU(cpuobj);
|
||||
cs->cpu_index = n;
|
||||
|
||||
numa_cpu_pre_plug(&possible_cpus->cpus[cs->cpu_index], DEVICE(cpuobj),
|
||||
&error_fatal);
|
||||
|
||||
if (object_property_find(cpuobj, "reset-cbar", NULL)) {
|
||||
object_property_set_int(cpuobj,
|
||||
sbsa_ref_memmap[SBSA_CPUPERIPHS].base,
|
||||
"reset-cbar", &error_abort);
|
||||
}
|
||||
|
||||
object_property_set_link(cpuobj, OBJECT(sysmem), "memory",
|
||||
&error_abort);
|
||||
|
||||
object_property_set_link(cpuobj, OBJECT(secure_sysmem),
|
||||
"secure-memory", &error_abort);
|
||||
|
||||
object_property_set_bool(cpuobj, true, "realized", &error_fatal);
|
||||
object_unref(cpuobj);
|
||||
}
|
||||
|
||||
memory_region_allocate_system_memory(ram, NULL, "sbsa-ref.ram",
|
||||
machine->ram_size);
|
||||
memory_region_add_subregion(sysmem, sbsa_ref_memmap[SBSA_MEM].base, ram);
|
||||
|
||||
create_fdt(sms);
|
||||
|
||||
create_secure_ram(sms, secure_sysmem);
|
||||
|
||||
create_gic(sms, pic);
|
||||
|
||||
create_uart(sms, pic, SBSA_UART, sysmem, serial_hd(0));
|
||||
create_uart(sms, pic, 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_rtc(sms, pic);
|
||||
|
||||
create_gpio(sms, pic);
|
||||
|
||||
create_ahci(sms, pic);
|
||||
|
||||
create_ehci(sms, pic);
|
||||
|
||||
create_pcie(sms, pic);
|
||||
|
||||
sms->bootinfo.ram_size = machine->ram_size;
|
||||
sms->bootinfo.kernel_filename = machine->kernel_filename;
|
||||
sms->bootinfo.nb_cpus = smp_cpus;
|
||||
sms->bootinfo.board_id = -1;
|
||||
sms->bootinfo.loader_start = sbsa_ref_memmap[SBSA_MEM].base;
|
||||
sms->bootinfo.get_dtb = sbsa_ref_dtb;
|
||||
sms->bootinfo.firmware_loaded = firmware_loaded;
|
||||
arm_load_kernel(ARM_CPU(first_cpu), &sms->bootinfo);
|
||||
}
|
||||
|
||||
static uint64_t sbsa_ref_cpu_mp_affinity(SBSAMachineState *sms, int idx)
|
||||
{
|
||||
uint8_t clustersz = ARM_DEFAULT_CPUS_PER_CLUSTER;
|
||||
return arm_cpu_mp_affinity(idx, clustersz);
|
||||
}
|
||||
|
||||
static const CPUArchIdList *sbsa_ref_possible_cpu_arch_ids(MachineState *ms)
|
||||
{
|
||||
SBSAMachineState *sms = SBSA_MACHINE(ms);
|
||||
int n;
|
||||
|
||||
if (ms->possible_cpus) {
|
||||
assert(ms->possible_cpus->len == max_cpus);
|
||||
return ms->possible_cpus;
|
||||
}
|
||||
|
||||
ms->possible_cpus = g_malloc0(sizeof(CPUArchIdList) +
|
||||
sizeof(CPUArchId) * max_cpus);
|
||||
ms->possible_cpus->len = max_cpus;
|
||||
for (n = 0; n < ms->possible_cpus->len; n++) {
|
||||
ms->possible_cpus->cpus[n].type = ms->cpu_type;
|
||||
ms->possible_cpus->cpus[n].arch_id =
|
||||
sbsa_ref_cpu_mp_affinity(sms, n);
|
||||
ms->possible_cpus->cpus[n].props.has_thread_id = true;
|
||||
ms->possible_cpus->cpus[n].props.thread_id = n;
|
||||
}
|
||||
return ms->possible_cpus;
|
||||
}
|
||||
|
||||
static CpuInstanceProperties
|
||||
sbsa_ref_cpu_index_to_props(MachineState *ms, unsigned cpu_index)
|
||||
{
|
||||
MachineClass *mc = MACHINE_GET_CLASS(ms);
|
||||
const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(ms);
|
||||
|
||||
assert(cpu_index < possible_cpus->len);
|
||||
return possible_cpus->cpus[cpu_index].props;
|
||||
}
|
||||
|
||||
static int64_t
|
||||
sbsa_ref_get_default_cpu_node_id(const MachineState *ms, int idx)
|
||||
{
|
||||
return idx % nb_numa_nodes;
|
||||
}
|
||||
|
||||
static void sbsa_ref_instance_init(Object *obj)
|
||||
{
|
||||
SBSAMachineState *sms = SBSA_MACHINE(obj);
|
||||
|
||||
sbsa_flash_create(sms);
|
||||
}
|
||||
|
||||
static void sbsa_ref_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
|
||||
mc->init = sbsa_ref_init;
|
||||
mc->desc = "QEMU 'SBSA Reference' ARM Virtual Machine";
|
||||
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a57");
|
||||
mc->max_cpus = 512;
|
||||
mc->pci_allow_0_address = true;
|
||||
mc->minimum_page_bits = 12;
|
||||
mc->block_default_type = IF_IDE;
|
||||
mc->no_cdrom = 1;
|
||||
mc->default_ram_size = 1 * GiB;
|
||||
mc->default_cpus = 4;
|
||||
mc->possible_cpu_arch_ids = sbsa_ref_possible_cpu_arch_ids;
|
||||
mc->cpu_index_to_instance_props = sbsa_ref_cpu_index_to_props;
|
||||
mc->get_default_cpu_node_id = sbsa_ref_get_default_cpu_node_id;
|
||||
}
|
||||
|
||||
static const TypeInfo sbsa_ref_info = {
|
||||
.name = TYPE_SBSA_MACHINE,
|
||||
.parent = TYPE_MACHINE,
|
||||
.instance_init = sbsa_ref_instance_init,
|
||||
.class_init = sbsa_ref_class_init,
|
||||
.instance_size = sizeof(SBSAMachineState),
|
||||
};
|
||||
|
||||
static void sbsa_ref_machine_init(void)
|
||||
{
|
||||
type_register_static(&sbsa_ref_info);
|
||||
}
|
||||
|
||||
type_init(sbsa_ref_machine_init);
|
|
@ -176,6 +176,7 @@ static const int a15irqmap[] = {
|
|||
};
|
||||
|
||||
static const char *valid_cpus[] = {
|
||||
ARM_CPU_TYPE_NAME("cortex-a7"),
|
||||
ARM_CPU_TYPE_NAME("cortex-a15"),
|
||||
ARM_CPU_TYPE_NAME("cortex-a53"),
|
||||
ARM_CPU_TYPE_NAME("cortex-a57"),
|
||||
|
|
|
@ -104,54 +104,63 @@ static void aspeed_vic_set_irq(void *opaque, int irq, int level)
|
|||
|
||||
static uint64_t aspeed_vic_read(void *opaque, hwaddr offset, unsigned size)
|
||||
{
|
||||
uint64_t val;
|
||||
const bool high = !!(offset & 0x4);
|
||||
hwaddr n_offset = (offset & ~0x4);
|
||||
AspeedVICState *s = (AspeedVICState *)opaque;
|
||||
hwaddr n_offset;
|
||||
uint64_t val;
|
||||
bool high;
|
||||
|
||||
if (offset < AVIC_NEW_BASE_OFFSET) {
|
||||
qemu_log_mask(LOG_UNIMP, "%s: Ignoring read from legacy registers "
|
||||
"at 0x%" HWADDR_PRIx "[%u]\n", __func__, offset, size);
|
||||
return 0;
|
||||
high = false;
|
||||
n_offset = offset;
|
||||
} else {
|
||||
high = !!(offset & 0x4);
|
||||
n_offset = (offset & ~0x4);
|
||||
}
|
||||
|
||||
n_offset -= AVIC_NEW_BASE_OFFSET;
|
||||
|
||||
switch (n_offset) {
|
||||
case 0x0: /* IRQ Status */
|
||||
case 0x80: /* IRQ Status */
|
||||
case 0x00:
|
||||
val = s->raw & ~s->select & s->enable;
|
||||
break;
|
||||
case 0x08: /* FIQ Status */
|
||||
case 0x88: /* FIQ Status */
|
||||
case 0x04:
|
||||
val = s->raw & s->select & s->enable;
|
||||
break;
|
||||
case 0x10: /* Raw Interrupt Status */
|
||||
case 0x90: /* Raw Interrupt Status */
|
||||
case 0x08:
|
||||
val = s->raw;
|
||||
break;
|
||||
case 0x18: /* Interrupt Selection */
|
||||
case 0x98: /* Interrupt Selection */
|
||||
case 0x0c:
|
||||
val = s->select;
|
||||
break;
|
||||
case 0x20: /* Interrupt Enable */
|
||||
case 0xa0: /* Interrupt Enable */
|
||||
case 0x10:
|
||||
val = s->enable;
|
||||
break;
|
||||
case 0x30: /* Software Interrupt */
|
||||
case 0xb0: /* Software Interrupt */
|
||||
case 0x18:
|
||||
val = s->trigger;
|
||||
break;
|
||||
case 0x40: /* Interrupt Sensitivity */
|
||||
case 0xc0: /* Interrupt Sensitivity */
|
||||
case 0x24:
|
||||
val = s->sense;
|
||||
break;
|
||||
case 0x48: /* Interrupt Both Edge Trigger Control */
|
||||
case 0xc8: /* Interrupt Both Edge Trigger Control */
|
||||
case 0x28:
|
||||
val = s->dual_edge;
|
||||
break;
|
||||
case 0x50: /* Interrupt Event */
|
||||
case 0xd0: /* Interrupt Event */
|
||||
case 0x2c:
|
||||
val = s->event;
|
||||
break;
|
||||
case 0x60: /* Edge Triggered Interrupt Status */
|
||||
case 0xe0: /* Edge Triggered Interrupt Status */
|
||||
val = s->raw & ~s->sense;
|
||||
break;
|
||||
/* Illegal */
|
||||
case 0x28: /* Interrupt Enable Clear */
|
||||
case 0x38: /* Software Interrupt Clear */
|
||||
case 0x58: /* Edge Triggered Interrupt Clear */
|
||||
case 0xa8: /* Interrupt Enable Clear */
|
||||
case 0xb8: /* Software Interrupt Clear */
|
||||
case 0xd8: /* Edge Triggered Interrupt Clear */
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Read of write-only register with offset 0x%"
|
||||
HWADDR_PRIx "\n", __func__, offset);
|
||||
|
@ -166,6 +175,8 @@ static uint64_t aspeed_vic_read(void *opaque, hwaddr offset, unsigned size)
|
|||
}
|
||||
if (high) {
|
||||
val = extract64(val, 32, 19);
|
||||
} else {
|
||||
val = extract64(val, 0, 32);
|
||||
}
|
||||
trace_aspeed_vic_read(offset, size, val);
|
||||
return val;
|
||||
|
@ -174,19 +185,18 @@ static uint64_t aspeed_vic_read(void *opaque, hwaddr offset, unsigned size)
|
|||
static void aspeed_vic_write(void *opaque, hwaddr offset, uint64_t data,
|
||||
unsigned size)
|
||||
{
|
||||
const bool high = !!(offset & 0x4);
|
||||
hwaddr n_offset = (offset & ~0x4);
|
||||
AspeedVICState *s = (AspeedVICState *)opaque;
|
||||
hwaddr n_offset;
|
||||
bool high;
|
||||
|
||||
if (offset < AVIC_NEW_BASE_OFFSET) {
|
||||
qemu_log_mask(LOG_UNIMP,
|
||||
"%s: Ignoring write to legacy registers at 0x%"
|
||||
HWADDR_PRIx "[%u] <- 0x%" PRIx64 "\n", __func__, offset,
|
||||
size, data);
|
||||
return;
|
||||
high = false;
|
||||
n_offset = offset;
|
||||
} else {
|
||||
high = !!(offset & 0x4);
|
||||
n_offset = (offset & ~0x4);
|
||||
}
|
||||
|
||||
n_offset -= AVIC_NEW_BASE_OFFSET;
|
||||
trace_aspeed_vic_write(offset, size, data);
|
||||
|
||||
/* Given we have members using separate enable/clear registers, deposit64()
|
||||
|
@ -201,7 +211,8 @@ static void aspeed_vic_write(void *opaque, hwaddr offset, uint64_t data,
|
|||
}
|
||||
|
||||
switch (n_offset) {
|
||||
case 0x18: /* Interrupt Selection */
|
||||
case 0x98: /* Interrupt Selection */
|
||||
case 0x0c:
|
||||
/* Register has deposit64() semantics - overwrite requested 32 bits */
|
||||
if (high) {
|
||||
s->select &= AVIC_L_MASK;
|
||||
|
@ -210,21 +221,25 @@ static void aspeed_vic_write(void *opaque, hwaddr offset, uint64_t data,
|
|||
}
|
||||
s->select |= data;
|
||||
break;
|
||||
case 0x20: /* Interrupt Enable */
|
||||
case 0xa0: /* Interrupt Enable */
|
||||
case 0x10:
|
||||
s->enable |= data;
|
||||
break;
|
||||
case 0x28: /* Interrupt Enable Clear */
|
||||
case 0xa8: /* Interrupt Enable Clear */
|
||||
case 0x14:
|
||||
s->enable &= ~data;
|
||||
break;
|
||||
case 0x30: /* Software Interrupt */
|
||||
case 0xb0: /* Software Interrupt */
|
||||
case 0x18:
|
||||
qemu_log_mask(LOG_UNIMP, "%s: Software interrupts unavailable. "
|
||||
"IRQs requested: 0x%016" PRIx64 "\n", __func__, data);
|
||||
break;
|
||||
case 0x38: /* Software Interrupt Clear */
|
||||
case 0xb8: /* Software Interrupt Clear */
|
||||
case 0x1c:
|
||||
qemu_log_mask(LOG_UNIMP, "%s: Software interrupts unavailable. "
|
||||
"IRQs to be cleared: 0x%016" PRIx64 "\n", __func__, data);
|
||||
break;
|
||||
case 0x50: /* Interrupt Event */
|
||||
case 0xd0: /* Interrupt Event */
|
||||
/* Register has deposit64() semantics - overwrite the top four valid
|
||||
* IRQ bits, as only the top four IRQs (GPIOs) can change their event
|
||||
* type */
|
||||
|
@ -236,15 +251,21 @@ static void aspeed_vic_write(void *opaque, hwaddr offset, uint64_t data,
|
|||
"Ignoring invalid write to interrupt event register");
|
||||
}
|
||||
break;
|
||||
case 0x58: /* Edge Triggered Interrupt Clear */
|
||||
case 0xd8: /* Edge Triggered Interrupt Clear */
|
||||
case 0x38:
|
||||
s->raw &= ~(data & ~s->sense);
|
||||
break;
|
||||
case 0x00: /* IRQ Status */
|
||||
case 0x08: /* FIQ Status */
|
||||
case 0x10: /* Raw Interrupt Status */
|
||||
case 0x40: /* Interrupt Sensitivity */
|
||||
case 0x48: /* Interrupt Both Edge Trigger Control */
|
||||
case 0x60: /* Edge Triggered Interrupt Status */
|
||||
case 0x80: /* IRQ Status */
|
||||
case 0x00:
|
||||
case 0x88: /* FIQ Status */
|
||||
case 0x04:
|
||||
case 0x90: /* Raw Interrupt Status */
|
||||
case 0x08:
|
||||
case 0xc0: /* Interrupt Sensitivity */
|
||||
case 0x24:
|
||||
case 0xc8: /* Interrupt Both Edge Trigger Control */
|
||||
case 0x28:
|
||||
case 0xe0: /* Edge Triggered Interrupt Status */
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Write of read-only register with offset 0x%"
|
||||
HWADDR_PRIx "\n", __func__, offset);
|
||||
|
|
|
@ -74,6 +74,7 @@ obj-$(CONFIG_ARMSSE_MHU) += armsse-mhu.o
|
|||
|
||||
obj-$(CONFIG_PVPANIC) += pvpanic.o
|
||||
obj-$(CONFIG_AUX) += auxbus.o
|
||||
obj-$(CONFIG_ASPEED_SOC) += aspeed_xdma.o
|
||||
obj-$(CONFIG_ASPEED_SOC) += aspeed_scu.o aspeed_sdmc.o
|
||||
obj-$(CONFIG_MSF2) += msf2-sysreg.o
|
||||
obj-$(CONFIG_NRF51_SOC) += nrf51_rng.o
|
||||
|
|
165
hw/misc/aspeed_xdma.c
Normal file
165
hw/misc/aspeed_xdma.c
Normal file
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
* ASPEED XDMA Controller
|
||||
* Eddie James <eajames@linux.ibm.com>
|
||||
*
|
||||
* Copyright (C) 2019 IBM Corp
|
||||
* SPDX-License-Identifer: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "hw/misc/aspeed_xdma.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
#include "trace.h"
|
||||
|
||||
#define XDMA_BMC_CMDQ_ADDR 0x10
|
||||
#define XDMA_BMC_CMDQ_ENDP 0x14
|
||||
#define XDMA_BMC_CMDQ_WRP 0x18
|
||||
#define XDMA_BMC_CMDQ_W_MASK 0x0003FFFF
|
||||
#define XDMA_BMC_CMDQ_RDP 0x1C
|
||||
#define XDMA_BMC_CMDQ_RDP_MAGIC 0xEE882266
|
||||
#define XDMA_IRQ_ENG_CTRL 0x20
|
||||
#define XDMA_IRQ_ENG_CTRL_US_COMP BIT(4)
|
||||
#define XDMA_IRQ_ENG_CTRL_DS_COMP BIT(5)
|
||||
#define XDMA_IRQ_ENG_CTRL_W_MASK 0xBFEFF07F
|
||||
#define XDMA_IRQ_ENG_STAT 0x24
|
||||
#define XDMA_IRQ_ENG_STAT_US_COMP BIT(4)
|
||||
#define XDMA_IRQ_ENG_STAT_DS_COMP BIT(5)
|
||||
#define XDMA_IRQ_ENG_STAT_RESET 0xF8000000
|
||||
#define XDMA_MEM_SIZE 0x1000
|
||||
|
||||
#define TO_REG(addr) ((addr) / sizeof(uint32_t))
|
||||
|
||||
static uint64_t aspeed_xdma_read(void *opaque, hwaddr addr, unsigned int size)
|
||||
{
|
||||
uint32_t val = 0;
|
||||
AspeedXDMAState *xdma = opaque;
|
||||
|
||||
if (addr < ASPEED_XDMA_REG_SIZE) {
|
||||
val = xdma->regs[TO_REG(addr)];
|
||||
}
|
||||
|
||||
return (uint64_t)val;
|
||||
}
|
||||
|
||||
static void aspeed_xdma_write(void *opaque, hwaddr addr, uint64_t val,
|
||||
unsigned int size)
|
||||
{
|
||||
unsigned int idx;
|
||||
uint32_t val32 = (uint32_t)val;
|
||||
AspeedXDMAState *xdma = opaque;
|
||||
|
||||
if (addr >= ASPEED_XDMA_REG_SIZE) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (addr) {
|
||||
case XDMA_BMC_CMDQ_ENDP:
|
||||
xdma->regs[TO_REG(addr)] = val32 & XDMA_BMC_CMDQ_W_MASK;
|
||||
break;
|
||||
case XDMA_BMC_CMDQ_WRP:
|
||||
idx = TO_REG(addr);
|
||||
xdma->regs[idx] = val32 & XDMA_BMC_CMDQ_W_MASK;
|
||||
xdma->regs[TO_REG(XDMA_BMC_CMDQ_RDP)] = xdma->regs[idx];
|
||||
|
||||
trace_aspeed_xdma_write(addr, val);
|
||||
|
||||
if (xdma->bmc_cmdq_readp_set) {
|
||||
xdma->bmc_cmdq_readp_set = 0;
|
||||
} else {
|
||||
xdma->regs[TO_REG(XDMA_IRQ_ENG_STAT)] |=
|
||||
XDMA_IRQ_ENG_STAT_US_COMP | XDMA_IRQ_ENG_STAT_DS_COMP;
|
||||
|
||||
if (xdma->regs[TO_REG(XDMA_IRQ_ENG_CTRL)] &
|
||||
(XDMA_IRQ_ENG_CTRL_US_COMP | XDMA_IRQ_ENG_CTRL_DS_COMP))
|
||||
qemu_irq_raise(xdma->irq);
|
||||
}
|
||||
break;
|
||||
case XDMA_BMC_CMDQ_RDP:
|
||||
trace_aspeed_xdma_write(addr, val);
|
||||
|
||||
if (val32 == XDMA_BMC_CMDQ_RDP_MAGIC) {
|
||||
xdma->bmc_cmdq_readp_set = 1;
|
||||
}
|
||||
break;
|
||||
case XDMA_IRQ_ENG_CTRL:
|
||||
xdma->regs[TO_REG(addr)] = val32 & XDMA_IRQ_ENG_CTRL_W_MASK;
|
||||
break;
|
||||
case XDMA_IRQ_ENG_STAT:
|
||||
trace_aspeed_xdma_write(addr, val);
|
||||
|
||||
idx = TO_REG(addr);
|
||||
if (val32 & (XDMA_IRQ_ENG_STAT_US_COMP | XDMA_IRQ_ENG_STAT_DS_COMP)) {
|
||||
xdma->regs[idx] &=
|
||||
~(XDMA_IRQ_ENG_STAT_US_COMP | XDMA_IRQ_ENG_STAT_DS_COMP);
|
||||
qemu_irq_lower(xdma->irq);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
xdma->regs[TO_REG(addr)] = val32;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps aspeed_xdma_ops = {
|
||||
.read = aspeed_xdma_read,
|
||||
.write = aspeed_xdma_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.valid.min_access_size = 4,
|
||||
.valid.max_access_size = 4,
|
||||
};
|
||||
|
||||
static void aspeed_xdma_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
AspeedXDMAState *xdma = ASPEED_XDMA(dev);
|
||||
|
||||
sysbus_init_irq(sbd, &xdma->irq);
|
||||
memory_region_init_io(&xdma->iomem, OBJECT(xdma), &aspeed_xdma_ops, xdma,
|
||||
TYPE_ASPEED_XDMA, XDMA_MEM_SIZE);
|
||||
sysbus_init_mmio(sbd, &xdma->iomem);
|
||||
}
|
||||
|
||||
static void aspeed_xdma_reset(DeviceState *dev)
|
||||
{
|
||||
AspeedXDMAState *xdma = ASPEED_XDMA(dev);
|
||||
|
||||
xdma->bmc_cmdq_readp_set = 0;
|
||||
memset(xdma->regs, 0, ASPEED_XDMA_REG_SIZE);
|
||||
xdma->regs[TO_REG(XDMA_IRQ_ENG_STAT)] = XDMA_IRQ_ENG_STAT_RESET;
|
||||
|
||||
qemu_irq_lower(xdma->irq);
|
||||
}
|
||||
|
||||
static const VMStateDescription aspeed_xdma_vmstate = {
|
||||
.name = TYPE_ASPEED_XDMA,
|
||||
.version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(regs, AspeedXDMAState, ASPEED_XDMA_NUM_REGS),
|
||||
VMSTATE_END_OF_LIST(),
|
||||
},
|
||||
};
|
||||
|
||||
static void aspeed_xdma_class_init(ObjectClass *classp, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(classp);
|
||||
|
||||
dc->realize = aspeed_xdma_realize;
|
||||
dc->reset = aspeed_xdma_reset;
|
||||
dc->vmsd = &aspeed_xdma_vmstate;
|
||||
}
|
||||
|
||||
static const TypeInfo aspeed_xdma_info = {
|
||||
.name = TYPE_ASPEED_XDMA,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(AspeedXDMAState),
|
||||
.class_init = aspeed_xdma_class_init,
|
||||
};
|
||||
|
||||
static void aspeed_xdma_register_type(void)
|
||||
{
|
||||
type_register_static(&aspeed_xdma_info);
|
||||
}
|
||||
type_init(aspeed_xdma_register_type);
|
|
@ -140,3 +140,6 @@ armsse_cpuid_write(uint64_t offset, uint64_t data, unsigned size) "SSE-200 CPU_I
|
|||
# armsse-mhu.c
|
||||
armsse_mhu_read(uint64_t offset, uint64_t data, unsigned size) "SSE-200 MHU read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
|
||||
armsse_mhu_write(uint64_t offset, uint64_t data, unsigned size) "SSE-200 MHU write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
|
||||
|
||||
# aspeed_xdma.c
|
||||
aspeed_xdma_write(uint64_t offset, uint64_t data) "XDMA write: offset 0x%" PRIx64 " data 0x%" PRIx64
|
||||
|
|
|
@ -51,6 +51,8 @@
|
|||
#define DESIGNWARE_PCIE_ATU_DEVFN(x) (((x) >> 16) & 0xff)
|
||||
#define DESIGNWARE_PCIE_ATU_UPPER_TARGET 0x91C
|
||||
|
||||
#define DESIGNWARE_PCIE_IRQ_MSI 3
|
||||
|
||||
static DesignwarePCIEHost *
|
||||
designware_pcie_root_to_host(DesignwarePCIERoot *root)
|
||||
{
|
||||
|
@ -67,7 +69,7 @@ static void designware_pcie_root_msi_write(void *opaque, hwaddr addr,
|
|||
root->msi.intr[0].status |= BIT(val) & root->msi.intr[0].enable;
|
||||
|
||||
if (root->msi.intr[0].status & ~root->msi.intr[0].mask) {
|
||||
qemu_set_irq(host->pci.irqs[0], 1);
|
||||
qemu_set_irq(host->pci.irqs[DESIGNWARE_PCIE_IRQ_MSI], 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -290,23 +292,19 @@ static void designware_pcie_root_config_write(PCIDevice *d, uint32_t address,
|
|||
case DESIGNWARE_PCIE_MSI_ADDR_LO:
|
||||
root->msi.base &= 0xFFFFFFFF00000000ULL;
|
||||
root->msi.base |= val;
|
||||
designware_pcie_root_update_msi_mapping(root);
|
||||
break;
|
||||
|
||||
case DESIGNWARE_PCIE_MSI_ADDR_HI:
|
||||
root->msi.base &= 0x00000000FFFFFFFFULL;
|
||||
root->msi.base |= (uint64_t)val << 32;
|
||||
designware_pcie_root_update_msi_mapping(root);
|
||||
break;
|
||||
|
||||
case DESIGNWARE_PCIE_MSI_INTR0_ENABLE: {
|
||||
const bool update_msi_mapping = !root->msi.intr[0].enable ^ !!val;
|
||||
|
||||
case DESIGNWARE_PCIE_MSI_INTR0_ENABLE:
|
||||
root->msi.intr[0].enable = val;
|
||||
|
||||
if (update_msi_mapping) {
|
||||
designware_pcie_root_update_msi_mapping(root);
|
||||
}
|
||||
designware_pcie_root_update_msi_mapping(root);
|
||||
break;
|
||||
}
|
||||
|
||||
case DESIGNWARE_PCIE_MSI_INTR0_MASK:
|
||||
root->msi.intr[0].mask = val;
|
||||
|
@ -315,7 +313,7 @@ static void designware_pcie_root_config_write(PCIDevice *d, uint32_t address,
|
|||
case DESIGNWARE_PCIE_MSI_INTR0_STATUS:
|
||||
root->msi.intr[0].status ^= val;
|
||||
if (!root->msi.intr[0].status) {
|
||||
qemu_set_irq(host->pci.irqs[0], 0);
|
||||
qemu_set_irq(host->pci.irqs[DESIGNWARE_PCIE_IRQ_MSI], 0);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -913,6 +913,7 @@ static const VMStateDescription vmstate_aspeed_smc = {
|
|||
|
||||
static Property aspeed_smc_properties[] = {
|
||||
DEFINE_PROP_UINT32("num-cs", AspeedSMCState, num_cs, 1),
|
||||
DEFINE_PROP_UINT64("sdram-base", AspeedSMCState, sdram_base, 0),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ obj-$(CONFIG_MC146818RTC) += mc146818rtc.o
|
|||
obj-$(CONFIG_ALLWINNER_A10_PIT) += allwinner-a10-pit.o
|
||||
|
||||
common-obj-$(CONFIG_STM32F2XX_TIMER) += stm32f2xx_timer.o
|
||||
common-obj-$(CONFIG_ASPEED_SOC) += aspeed_timer.o
|
||||
common-obj-$(CONFIG_ASPEED_SOC) += aspeed_timer.o aspeed_rtc.o
|
||||
|
||||
common-obj-$(CONFIG_SUN4V_RTC) += sun4v-rtc.o
|
||||
common-obj-$(CONFIG_CMSDK_APB_TIMER) += cmsdk-apb-timer.o
|
||||
|
|
180
hw/timer/aspeed_rtc.c
Normal file
180
hw/timer/aspeed_rtc.c
Normal file
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
* ASPEED Real Time Clock
|
||||
* Joel Stanley <joel@jms.id.au>
|
||||
*
|
||||
* Copyright 2019 IBM Corp
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "hw/timer/aspeed_rtc.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/timer.h"
|
||||
|
||||
#include "trace.h"
|
||||
|
||||
#define COUNTER1 (0x00 / 4)
|
||||
#define COUNTER2 (0x04 / 4)
|
||||
#define ALARM (0x08 / 4)
|
||||
#define CONTROL (0x10 / 4)
|
||||
#define ALARM_STATUS (0x14 / 4)
|
||||
|
||||
#define RTC_UNLOCKED BIT(1)
|
||||
#define RTC_ENABLED BIT(0)
|
||||
|
||||
static void aspeed_rtc_calc_offset(AspeedRtcState *rtc)
|
||||
{
|
||||
struct tm tm;
|
||||
uint32_t year, cent;
|
||||
uint32_t reg1 = rtc->reg[COUNTER1];
|
||||
uint32_t reg2 = rtc->reg[COUNTER2];
|
||||
|
||||
tm.tm_mday = (reg1 >> 24) & 0x1f;
|
||||
tm.tm_hour = (reg1 >> 16) & 0x1f;
|
||||
tm.tm_min = (reg1 >> 8) & 0x3f;
|
||||
tm.tm_sec = (reg1 >> 0) & 0x3f;
|
||||
|
||||
cent = (reg2 >> 16) & 0x1f;
|
||||
year = (reg2 >> 8) & 0x7f;
|
||||
tm.tm_mon = ((reg2 >> 0) & 0x0f) - 1;
|
||||
tm.tm_year = year + (cent * 100) - 1900;
|
||||
|
||||
rtc->offset = qemu_timedate_diff(&tm);
|
||||
}
|
||||
|
||||
static uint32_t aspeed_rtc_get_counter(AspeedRtcState *rtc, int r)
|
||||
{
|
||||
uint32_t year, cent;
|
||||
struct tm now;
|
||||
|
||||
qemu_get_timedate(&now, rtc->offset);
|
||||
|
||||
switch (r) {
|
||||
case COUNTER1:
|
||||
return (now.tm_mday << 24) | (now.tm_hour << 16) |
|
||||
(now.tm_min << 8) | now.tm_sec;
|
||||
case COUNTER2:
|
||||
cent = (now.tm_year + 1900) / 100;
|
||||
year = now.tm_year % 100;
|
||||
return ((cent & 0x1f) << 16) | ((year & 0x7f) << 8) |
|
||||
((now.tm_mon + 1) & 0xf);
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t aspeed_rtc_read(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
AspeedRtcState *rtc = opaque;
|
||||
uint64_t val;
|
||||
uint32_t r = addr >> 2;
|
||||
|
||||
switch (r) {
|
||||
case COUNTER1:
|
||||
case COUNTER2:
|
||||
if (rtc->reg[CONTROL] & RTC_ENABLED) {
|
||||
rtc->reg[r] = aspeed_rtc_get_counter(rtc, r);
|
||||
}
|
||||
/* fall through */
|
||||
case CONTROL:
|
||||
val = rtc->reg[r];
|
||||
break;
|
||||
case ALARM:
|
||||
case ALARM_STATUS:
|
||||
default:
|
||||
qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx "\n", __func__, addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
trace_aspeed_rtc_read(addr, val);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static void aspeed_rtc_write(void *opaque, hwaddr addr,
|
||||
uint64_t val, unsigned size)
|
||||
{
|
||||
AspeedRtcState *rtc = opaque;
|
||||
uint32_t r = addr >> 2;
|
||||
|
||||
switch (r) {
|
||||
case COUNTER1:
|
||||
case COUNTER2:
|
||||
if (!(rtc->reg[CONTROL] & RTC_UNLOCKED)) {
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
case CONTROL:
|
||||
rtc->reg[r] = val;
|
||||
aspeed_rtc_calc_offset(rtc);
|
||||
break;
|
||||
case ALARM:
|
||||
case ALARM_STATUS:
|
||||
default:
|
||||
qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx "\n", __func__, addr);
|
||||
break;
|
||||
}
|
||||
trace_aspeed_rtc_write(addr, val);
|
||||
}
|
||||
|
||||
static void aspeed_rtc_reset(DeviceState *d)
|
||||
{
|
||||
AspeedRtcState *rtc = ASPEED_RTC(d);
|
||||
|
||||
rtc->offset = 0;
|
||||
memset(rtc->reg, 0, sizeof(rtc->reg));
|
||||
}
|
||||
|
||||
static const MemoryRegionOps aspeed_rtc_ops = {
|
||||
.read = aspeed_rtc_read,
|
||||
.write = aspeed_rtc_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_aspeed_rtc = {
|
||||
.name = TYPE_ASPEED_RTC,
|
||||
.version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(reg, AspeedRtcState, 0x18),
|
||||
VMSTATE_INT32(offset, AspeedRtcState),
|
||||
VMSTATE_INT32(offset, AspeedRtcState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void aspeed_rtc_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
AspeedRtcState *s = ASPEED_RTC(dev);
|
||||
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_rtc_ops, s,
|
||||
"aspeed-rtc", 0x18ULL);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
}
|
||||
|
||||
static void aspeed_rtc_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = aspeed_rtc_realize;
|
||||
dc->vmsd = &vmstate_aspeed_rtc;
|
||||
dc->reset = aspeed_rtc_reset;
|
||||
}
|
||||
|
||||
static const TypeInfo aspeed_rtc_info = {
|
||||
.name = TYPE_ASPEED_RTC,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(AspeedRtcState),
|
||||
.class_init = aspeed_rtc_class_init,
|
||||
};
|
||||
|
||||
static void aspeed_rtc_register_types(void)
|
||||
{
|
||||
type_register_static(&aspeed_rtc_info);
|
||||
}
|
||||
|
||||
type_init(aspeed_rtc_register_types)
|
|
@ -107,39 +107,49 @@ static inline uint64_t calculate_time(struct AspeedTimer *t, uint32_t ticks)
|
|||
return t->start + delta_ns;
|
||||
}
|
||||
|
||||
static inline uint32_t calculate_match(struct AspeedTimer *t, int i)
|
||||
{
|
||||
return t->match[i] < t->reload ? t->match[i] : 0;
|
||||
}
|
||||
|
||||
static uint64_t calculate_next(struct AspeedTimer *t)
|
||||
{
|
||||
uint64_t next = 0;
|
||||
uint32_t rate = calculate_rate(t);
|
||||
uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
uint64_t next;
|
||||
|
||||
while (!next) {
|
||||
/* We don't know the relationship between the values in the match
|
||||
* registers, so sort using MAX/MIN/zero. We sort in that order as the
|
||||
* timer counts down to zero. */
|
||||
uint64_t seq[] = {
|
||||
calculate_time(t, MAX(t->match[0], t->match[1])),
|
||||
calculate_time(t, MIN(t->match[0], t->match[1])),
|
||||
calculate_time(t, 0),
|
||||
};
|
||||
uint64_t reload_ns;
|
||||
uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
/*
|
||||
* We don't know the relationship between the values in the match
|
||||
* registers, so sort using MAX/MIN/zero. We sort in that order as
|
||||
* the timer counts down to zero.
|
||||
*/
|
||||
|
||||
if (now < seq[0]) {
|
||||
next = seq[0];
|
||||
} else if (now < seq[1]) {
|
||||
next = seq[1];
|
||||
} else if (now < seq[2]) {
|
||||
next = seq[2];
|
||||
} else if (t->reload) {
|
||||
reload_ns = muldiv64(t->reload, NANOSECONDS_PER_SECOND, rate);
|
||||
t->start = now - ((now - t->start) % reload_ns);
|
||||
} else {
|
||||
/* no reload value, return 0 */
|
||||
break;
|
||||
}
|
||||
next = calculate_time(t, MAX(calculate_match(t, 0), calculate_match(t, 1)));
|
||||
if (now < next) {
|
||||
return next;
|
||||
}
|
||||
|
||||
return next;
|
||||
next = calculate_time(t, MIN(calculate_match(t, 0), calculate_match(t, 1)));
|
||||
if (now < next) {
|
||||
return next;
|
||||
}
|
||||
|
||||
next = calculate_time(t, 0);
|
||||
if (now < next) {
|
||||
return next;
|
||||
}
|
||||
|
||||
/* We've missed all deadlines, fire interrupt and try again */
|
||||
timer_del(&t->timer);
|
||||
|
||||
if (timer_overflow_interrupt(t)) {
|
||||
t->level = !t->level;
|
||||
qemu_set_irq(t->irq, t->level);
|
||||
}
|
||||
|
||||
next = MAX(MAX(calculate_match(t, 0), calculate_match(t, 1)), 0);
|
||||
t->start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
|
||||
return calculate_time(t, next);
|
||||
}
|
||||
|
||||
static void aspeed_timer_mod(AspeedTimer *t)
|
||||
|
@ -184,7 +194,11 @@ static uint64_t aspeed_timer_get_value(AspeedTimer *t, int reg)
|
|||
|
||||
switch (reg) {
|
||||
case TIMER_REG_STATUS:
|
||||
value = calculate_ticks(t, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
|
||||
if (timer_enabled(t)) {
|
||||
value = calculate_ticks(t, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
|
||||
} else {
|
||||
value = t->reload;
|
||||
}
|
||||
break;
|
||||
case TIMER_REG_RELOAD:
|
||||
value = t->reload;
|
||||
|
@ -261,7 +275,11 @@ static void aspeed_timer_set_value(AspeedTimerCtrlState *s, int timer, int reg,
|
|||
int64_t delta = (int64_t) value - (int64_t) calculate_ticks(t, now);
|
||||
uint32_t rate = calculate_rate(t);
|
||||
|
||||
t->start += muldiv64(delta, NANOSECONDS_PER_SECOND, rate);
|
||||
if (delta >= 0) {
|
||||
t->start += muldiv64(delta, NANOSECONDS_PER_SECOND, rate);
|
||||
} else {
|
||||
t->start -= muldiv64(-delta, NANOSECONDS_PER_SECOND, rate);
|
||||
}
|
||||
aspeed_timer_mod(t);
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -66,6 +66,10 @@ cmsdk_apb_dualtimer_read(uint64_t offset, uint64_t data, unsigned size) "CMSDK A
|
|||
cmsdk_apb_dualtimer_write(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB dualtimer write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
|
||||
cmsdk_apb_dualtimer_reset(void) "CMSDK APB dualtimer: reset"
|
||||
|
||||
# hw/timer/aspeed-rtc.c
|
||||
aspeed_rtc_read(uint64_t addr, uint64_t value) "addr 0x%02" PRIx64 " value 0x%08" PRIx64
|
||||
aspeed_rtc_write(uint64_t addr, uint64_t value) "addr 0x%02" PRIx64 " value 0x%08" PRIx64
|
||||
|
||||
# sun4v-rtc.c
|
||||
sun4v_rtc_read(uint64_t addr, uint64_t value) "read: addr 0x%" PRIx64 " value 0x%" PRIx64
|
||||
sun4v_rtc_write(uint64_t addr, uint64_t value) "write: addr 0x%" PRIx64 " value 0x%" PRIx64
|
||||
|
|
|
@ -44,6 +44,9 @@
|
|||
|
||||
#define WDT_RESTART_MAGIC 0x4755
|
||||
|
||||
#define SCU_RESET_CONTROL1 (0x04 / 4)
|
||||
#define SCU_RESET_SDRAM BIT(0)
|
||||
|
||||
static bool aspeed_wdt_is_enabled(const AspeedWDTState *s)
|
||||
{
|
||||
return s->regs[WDT_CTRL] & WDT_CTRL_ENABLE;
|
||||
|
@ -222,6 +225,13 @@ static void aspeed_wdt_timer_expired(void *dev)
|
|||
{
|
||||
AspeedWDTState *s = ASPEED_WDT(dev);
|
||||
|
||||
/* Do not reset on SDRAM controller reset */
|
||||
if (s->scu->regs[SCU_RESET_CONTROL1] & SCU_RESET_SDRAM) {
|
||||
timer_del(s->timer);
|
||||
s->regs[WDT_CTRL] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
qemu_log_mask(CPU_LOG_RESET, "Watchdog timer expired.\n");
|
||||
watchdog_perform_action();
|
||||
timer_del(s->timer);
|
||||
|
@ -233,6 +243,16 @@ 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);
|
||||
|
||||
if (!is_supported_silicon_rev(s->silicon_rev)) {
|
||||
error_setg(errp, "Unknown silicon revision: 0x%" PRIx32,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue