aspeed queue:

* Introduce a new ASPEED OTP memory device model integrated with the
   Secure Boot Controller. It includes a new block device backend
   ('drive' property), is enabled for AST2600 SoCs and AST1030 SoCs.
   Functional tests are included
 * Changed "ast2700-evb" alias to point to the "ast2700a1-evb" machine
 * Introduce support for Aspeed PCIe host controller, including models
   for the PCIe Root Complex, Root Port, and PHY. Enabled for the
   AST2600 and AST2700 SoCs, and functional tests are included
 * Refactor Boot ROM support to improve code reuse across the different
   Aspeed machine. This is in preparation of vbootrom support in the
   ast2700fc machine
 * Improved Error Handling in the AST27x0-fc machine init functions
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEoPZlSPBIlev+awtgUaNDx8/77KEFAmjauRoACgkQUaNDx8/7
 7KGAxA//YdPPGf8vKhPeblUt0/3760GGhI17TBWJFVZP/aZYcIiE0oRxo5zH0Lne
 YjwFKTtx7GXzbE2wqVCLSt/VPDAEMk6wZGwGvMbmeydssyNjbPuF79+EVYnFsUrQ
 Zkm8YPf/qFcKYFxp8O5GTKedAu70AFDMkFwy2xuBRqE5v0RQJe20+EHaiEC8S+3a
 z5PIZJ74J3m4d+h+BlIHoiPe7hwTiyQ8V4rrWKWupwqDBExZfgNGX0zGPZDOlwOo
 bpV38gb0ugyG93/FJSXyXQqiiH5h+10CaSzc1QuytYtQXAM2qj60Kh86YruTsbLu
 g3TUz+jOgDatTk/MhH8q/gtwDjmqcygGeybbMJZeCzhq1qLIFgJW2KwPNwj8eHCd
 7jZp6NT9GekVMB+FghApWjc63EozKveJ3wzyHE481GGF7TgvuVF1Km+dVHNPjpBz
 pjXgIeKmDl0hmgGp3Se9S8B1ryWK3+KvuNoKe63UK/NMCkSXF3xTerkU1evJjIrp
 B9Tus7kLRqbDGWPyprp1d7Jv6MKJ6sELKvGHlalMcnzo4vAvQu1RB5s1kYqsCGlY
 414Bc2v/YdkLxQGU6hCp1rABq3sIdWVzxRJ4c0XalRNZBkOmlsy1p5FaG5RXQdhz
 Gm27nzDAWBeNmWD6Jjjj6VwWmqBbSO4M4mYVTMnTfEaO7y/l1d4=
 =7BzG
 -----END PGP SIGNATURE-----

Merge tag 'pull-aspeed-20250929' of https://github.com/legoater/qemu into staging

aspeed queue:

* Introduce a new ASPEED OTP memory device model integrated with the
  Secure Boot Controller. It includes a new block device backend
  ('drive' property), is enabled for AST2600 SoCs and AST1030 SoCs.
  Functional tests are included
* Changed "ast2700-evb" alias to point to the "ast2700a1-evb" machine
* Introduce support for Aspeed PCIe host controller, including models
  for the PCIe Root Complex, Root Port, and PHY. Enabled for the
  AST2600 and AST2700 SoCs, and functional tests are included
* Refactor Boot ROM support to improve code reuse across the different
  Aspeed machine. This is in preparation of vbootrom support in the
  ast2700fc machine
* Improved Error Handling in the AST27x0-fc machine init functions

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEEoPZlSPBIlev+awtgUaNDx8/77KEFAmjauRoACgkQUaNDx8/7
# 7KGAxA//YdPPGf8vKhPeblUt0/3760GGhI17TBWJFVZP/aZYcIiE0oRxo5zH0Lne
# YjwFKTtx7GXzbE2wqVCLSt/VPDAEMk6wZGwGvMbmeydssyNjbPuF79+EVYnFsUrQ
# Zkm8YPf/qFcKYFxp8O5GTKedAu70AFDMkFwy2xuBRqE5v0RQJe20+EHaiEC8S+3a
# z5PIZJ74J3m4d+h+BlIHoiPe7hwTiyQ8V4rrWKWupwqDBExZfgNGX0zGPZDOlwOo
# bpV38gb0ugyG93/FJSXyXQqiiH5h+10CaSzc1QuytYtQXAM2qj60Kh86YruTsbLu
# g3TUz+jOgDatTk/MhH8q/gtwDjmqcygGeybbMJZeCzhq1qLIFgJW2KwPNwj8eHCd
# 7jZp6NT9GekVMB+FghApWjc63EozKveJ3wzyHE481GGF7TgvuVF1Km+dVHNPjpBz
# pjXgIeKmDl0hmgGp3Se9S8B1ryWK3+KvuNoKe63UK/NMCkSXF3xTerkU1evJjIrp
# B9Tus7kLRqbDGWPyprp1d7Jv6MKJ6sELKvGHlalMcnzo4vAvQu1RB5s1kYqsCGlY
# 414Bc2v/YdkLxQGU6hCp1rABq3sIdWVzxRJ4c0XalRNZBkOmlsy1p5FaG5RXQdhz
# Gm27nzDAWBeNmWD6Jjjj6VwWmqBbSO4M4mYVTMnTfEaO7y/l1d4=
# =7BzG
# -----END PGP SIGNATURE-----
# gpg: Signature made Mon 29 Sep 2025 09:51:38 AM PDT
# gpg:                using RSA key A0F66548F04895EBFE6B0B6051A343C7CFFBECA1
# gpg: Good signature from "Cédric Le Goater <clg@redhat.com>" [full]
# gpg:                 aka "Cédric Le Goater <clg@kaod.org>" [full]

* tag 'pull-aspeed-20250929' of https://github.com/legoater/qemu: (32 commits)
  hw/arm/aspeed_ast27x0-fc: Make sub-init functions return bool with errp
  hw/arm/aspeed_ast27x0-fc: Drop dead return checks
  hw/arm/aspeed: Move aspeed_load_vbootrom to common SoC code
  hw/arm/aspeed: Move aspeed_install_boot_rom to common SoC code
  hw/arm/aspeed: Move write_boot_rom to common SoC code
  hw/arm/aspeed: Move aspeed_board_init_flashes() to common SoC code
  tests/functional/arm/test_aspeed_ast2600: Add PCIe and network test
  hw/arm/aspeed_ast27x0: Introduce 3 PCIe RCs for AST2700
  hw/pci-host/aspeed: Disable Root Device and place Root Port at 00:00.0 to AST2700
  hw/pci-host/aspeed: Add AST2700 PCIe config with dedicated H2X blocks
  hw/pci-host/aspeed: Add AST2700 PCIe PHY
  hw/arm/aspeed_ast2600: Add PCIe RC support (RC_H only)
  hw/arm/aspeed: Wire up PCIe devices in SoC model
  hw/pci-host/aspeed: Add MSI support and per-RC IOMMU address space
  hw/pci-host/aspeed: Add AST2600 PCIe Root Port and make address configurable
  hw/pci-host/aspeed: Add AST2600 PCIe Root Device support
  hw/pci-host/aspeed: Add AST2600 PCIe config space and host bridge
  hw/pci-host/aspeed: Add AST2600 PCIe PHY model
  hw/pci/pci_ids: Add PCI vendor ID for ASPEED
  tests/functional/arm: Add AST2600 boot test with generated OTP image
  ...

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2025-09-29 10:52:48 -07:00
commit 85a3fd1c4c
26 changed files with 2019 additions and 153 deletions

View file

@ -243,6 +243,37 @@ under Linux), use :
-M ast2500-evb,bmc-console=uart3
OTP Option
^^^^^^^^^^
Both the AST2600 and AST1030 chips use the same One Time Programmable
(OTP) memory module, which is utilized for configuration, key storage,
and storing user-programmable data. This OTP memory module is managed
by the Secure Boot Controller (SBC). The following options can be
specified or omitted based on your needs.
* When the options are specified, the pre-generated configuration
file will be used as the OTP memory storage.
* When the options are omitted, an internal memory buffer will be
used to store the OTP memory data.
.. code-block:: bash
-blockdev driver=file,filename=otpmem.img,node-name=otp \
-global aspeed-otp.drive=otp \
The following bash command can be used to generate a default
configuration file for OTP memory:
.. code-block:: bash
if [ ! -f otpmem.img ]; then
for i in $(seq 1 2048); do
printf '\x00\x00\x00\x00\xff\xff\xff\xff'
done > otpmem.img
fi
Aspeed 2700 family boards (``ast2700-evb``)
==================================================================

View file

@ -541,6 +541,7 @@ config ASPEED_SOC
bool
default y
depends on TCG && ARM
imply PCI_DEVICES
select DS1338
select FTGMAC100
select I2C
@ -561,6 +562,8 @@ config ASPEED_SOC
select MAX31785
select FSI_APB2OPB_ASPEED
select AT24C
select PCI_EXPRESS
select PCI_EXPRESS_ASPEED
config MPS2
bool

View file

@ -26,9 +26,7 @@
#include "hw/qdev-properties.h"
#include "system/block-backend.h"
#include "system/reset.h"
#include "hw/loader.h"
#include "qemu/error-report.h"
#include "qemu/datadir.h"
#include "qemu/units.h"
#include "hw/qdev-clock.h"
#include "system/system.h"
@ -263,102 +261,6 @@ static void aspeed_reset_secondary(ARMCPU *cpu,
cpu_set_pc(cs, info->smp_loader_start);
}
static void write_boot_rom(BlockBackend *blk, hwaddr addr, size_t rom_size,
Error **errp)
{
g_autofree void *storage = NULL;
int64_t size;
/*
* The block backend size should have already been 'validated' by
* the creation of the m25p80 object.
*/
size = blk_getlength(blk);
if (size <= 0) {
error_setg(errp, "failed to get flash size");
return;
}
if (rom_size > size) {
rom_size = size;
}
storage = g_malloc0(rom_size);
if (blk_pread(blk, 0, rom_size, storage, 0) < 0) {
error_setg(errp, "failed to read the initial flash content");
return;
}
rom_add_blob_fixed("aspeed.boot_rom", storage, rom_size, addr);
}
/*
* Create a ROM and copy the flash contents at the expected address
* (0x0). Boots faster than execute-in-place.
*/
static void aspeed_install_boot_rom(AspeedMachineState *bmc, BlockBackend *blk,
uint64_t rom_size)
{
AspeedSoCState *soc = bmc->soc;
AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(soc);
memory_region_init_rom(&bmc->boot_rom, NULL, "aspeed.boot_rom", rom_size,
&error_abort);
memory_region_add_subregion_overlap(&soc->spi_boot_container, 0,
&bmc->boot_rom, 1);
write_boot_rom(blk, sc->memmap[ASPEED_DEV_SPI_BOOT],
rom_size, &error_abort);
}
#define VBOOTROM_FILE_NAME "ast27x0_bootrom.bin"
/*
* This function locates the vbootrom image file specified via the command line
* using the -bios option. It loads the specified image into the vbootrom
* memory region and handles errors if the file cannot be found or loaded.
*/
static void aspeed_load_vbootrom(AspeedMachineState *bmc, const char *bios_name,
Error **errp)
{
g_autofree char *filename = NULL;
AspeedSoCState *soc = bmc->soc;
int ret;
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
if (!filename) {
error_setg(errp, "Could not find vbootrom image '%s'", bios_name);
return;
}
ret = load_image_mr(filename, &soc->vbootrom);
if (ret < 0) {
error_setg(errp, "Failed to load vbootrom image '%s'", bios_name);
return;
}
}
void aspeed_board_init_flashes(AspeedSMCState *s, const char *flashtype,
unsigned int count, int unit0)
{
int i;
if (!flashtype) {
return;
}
for (i = 0; i < count; ++i) {
DriveInfo *dinfo = drive_get(IF_MTD, 0, unit0 + i);
DeviceState *dev;
dev = qdev_new(flashtype);
if (dinfo) {
qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(dinfo));
}
qdev_prop_set_uint8(dev, "cs", i);
qdev_realize_and_unref(dev, BUS(s->spi), &error_fatal);
}
}
static void sdhci_attach_drive(SDHCIState *sdhci, DriveInfo *dinfo, bool emmc,
bool boot_emmc)
{
@ -511,15 +413,16 @@ static void aspeed_machine_init(MachineState *machine)
if (fmc0 && !boot_emmc) {
uint64_t rom_size = memory_region_size(&bmc->soc->spi_boot);
aspeed_install_boot_rom(bmc, fmc0, rom_size);
aspeed_install_boot_rom(bmc->soc, fmc0, &bmc->boot_rom, rom_size);
} else if (emmc0) {
aspeed_install_boot_rom(bmc, blk_by_legacy_dinfo(emmc0), 64 * KiB);
aspeed_install_boot_rom(bmc->soc, blk_by_legacy_dinfo(emmc0),
&bmc->boot_rom, 64 * KiB);
}
}
if (amc->vbootrom) {
bios_name = machine->firmware ?: VBOOTROM_FILE_NAME;
aspeed_load_vbootrom(bmc, bios_name, &error_abort);
aspeed_load_vbootrom(bmc->soc, bios_name, &error_abort);
}
arm_load_kernel(ARM_CPU(first_cpu), machine, &aspeed_board_binfo);
@ -1995,7 +1898,6 @@ static void aspeed_machine_ast2700a0_evb_class_init(ObjectClass *oc,
MachineClass *mc = MACHINE_CLASS(oc);
AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
mc->alias = "ast2700-evb";
mc->desc = "Aspeed AST2700 A0 EVB (Cortex-A35)";
amc->soc_name = "ast2700-a0";
amc->hw_strap1 = AST2700_EVB_HW_STRAP1;
@ -2018,6 +1920,7 @@ static void aspeed_machine_ast2700a1_evb_class_init(ObjectClass *oc,
MachineClass *mc = MACHINE_CLASS(oc);
AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
mc->alias = "ast2700-evb";
mc->desc = "Aspeed AST2700 A1 EVB (Cortex-A35)";
amc->soc_name = "ast2700-a1";
amc->hw_strap1 = AST2700_EVB_HW_STRAP1;

View file

@ -154,7 +154,7 @@ static void aspeed_soc_ast1030_init(Object *obj)
object_initialize_child(obj, "peci", &s->peci, TYPE_ASPEED_PECI);
object_initialize_child(obj, "sbc", &s->sbc, TYPE_ASPEED_SBC);
object_initialize_child(obj, "sbc", &s->sbc, TYPE_ASPEED_AST10X0_SBC);
for (i = 0; i < sc->wdts_num; i++) {
snprintf(typename, sizeof(typename), "aspeed.wdt-%s", socname);

View file

@ -48,11 +48,13 @@ static const hwaddr aspeed_soc_ast2600_memmap[] = {
[ASPEED_DEV_XDMA] = 0x1E6E7000,
[ASPEED_DEV_ADC] = 0x1E6E9000,
[ASPEED_DEV_DP] = 0x1E6EB000,
[ASPEED_DEV_PCIE_PHY1] = 0x1E6ED200,
[ASPEED_DEV_SBC] = 0x1E6F2000,
[ASPEED_DEV_EMMC_BC] = 0x1E6f5000,
[ASPEED_DEV_VIDEO] = 0x1E700000,
[ASPEED_DEV_SDHCI] = 0x1E740000,
[ASPEED_DEV_EMMC] = 0x1E750000,
[ASPEED_DEV_PCIE0] = 0x1E770000,
[ASPEED_DEV_GPIO] = 0x1E780000,
[ASPEED_DEV_GPIO_1_8V] = 0x1E780800,
[ASPEED_DEV_RTC] = 0x1E781000,
@ -79,6 +81,7 @@ static const hwaddr aspeed_soc_ast2600_memmap[] = {
[ASPEED_DEV_FSI1] = 0x1E79B000,
[ASPEED_DEV_FSI2] = 0x1E79B100,
[ASPEED_DEV_I3C] = 0x1E7A0000,
[ASPEED_DEV_PCIE_MMIO1] = 0x70000000,
[ASPEED_DEV_SDRAM] = 0x80000000,
};
@ -127,6 +130,7 @@ static const int aspeed_soc_ast2600_irqmap[] = {
[ASPEED_DEV_LPC] = 35,
[ASPEED_DEV_IBT] = 143,
[ASPEED_DEV_I2C] = 110, /* 110 -> 125 */
[ASPEED_DEV_PCIE0] = 168,
[ASPEED_DEV_PECI] = 38,
[ASPEED_DEV_ETH1] = 2,
[ASPEED_DEV_ETH2] = 3,
@ -191,6 +195,10 @@ static void aspeed_soc_ast2600_init(Object *obj)
snprintf(typename, sizeof(typename), "aspeed.i2c-%s", socname);
object_initialize_child(obj, "i2c", &s->i2c, typename);
object_initialize_child(obj, "pcie-cfg", &s->pcie[0], TYPE_ASPEED_PCIE_CFG);
object_initialize_child(obj, "pcie-phy[*]", &s->pcie_phy[0],
TYPE_ASPEED_PCIE_PHY);
object_initialize_child(obj, "peci", &s->peci, TYPE_ASPEED_PECI);
snprintf(typename, sizeof(typename), "aspeed.fmc-%s", socname);
@ -261,7 +269,7 @@ static void aspeed_soc_ast2600_init(Object *obj)
object_initialize_child(obj, "i3c", &s->i3c, TYPE_ASPEED_I3C);
object_initialize_child(obj, "sbc", &s->sbc, TYPE_ASPEED_SBC);
object_initialize_child(obj, "sbc", &s->sbc, TYPE_ASPEED_AST2600_SBC);
object_initialize_child(obj, "iomem", &s->iomem, TYPE_UNIMPLEMENTED_DEVICE);
object_initialize_child(obj, "video", &s->video, TYPE_UNIMPLEMENTED_DEVICE);
@ -285,6 +293,67 @@ static uint64_t aspeed_calc_affinity(int cpu)
return (0xf << ARM_AFF1_SHIFT) | cpu;
}
/*
* PCIe Root Complex (RC)
*
* H2X register space (single block 0x00-0xFF):
* 0x00-0x7F : shared by RC_L (PCIe0) and RC_H (PCIe1)
* 0x80-0xBF : RC_L only
* 0xC0-0xFF : RC_H only
*
* Model scope / limitations:
* - Firmware supports RC_H only; this QEMU model does not support RC_L.
* - RC_H uses PHY1 and the MMIO window [0x70000000, 0x80000000]
* (aka MMIO1).
*
* Indexing convention (this model):
* - Expose a single logical instance at index 0.
* - pcie[0] -> hardware RC_H (PCIe1)
* - phy[0] -> hardware PHY1
* - mmio.0 -> guest address range MMIO1: 0x70000000-0x80000000
* - RC_L / PCIe0 is not created and mapped.
*/
static bool aspeed_soc_ast2600_pcie_realize(DeviceState *dev, Error **errp)
{
Aspeed2600SoCState *a = ASPEED2600_SOC(dev);
AspeedSoCState *s = ASPEED_SOC(dev);
AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
MemoryRegion *mmio_mr = NULL;
qemu_irq irq;
if (!sysbus_realize(SYS_BUS_DEVICE(&s->pcie_phy[0]), errp)) {
return false;
}
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->pcie_phy[0]), 0,
sc->memmap[ASPEED_DEV_PCIE_PHY1]);
object_property_set_int(OBJECT(&s->pcie[0]), "dram-base",
sc->memmap[ASPEED_DEV_SDRAM],
&error_abort);
object_property_set_link(OBJECT(&s->pcie[0]), "dram", OBJECT(s->dram_mr),
&error_abort);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->pcie[0]), errp)) {
return false;
}
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->pcie[0]), 0,
sc->memmap[ASPEED_DEV_PCIE0]);
irq = qdev_get_gpio_in(DEVICE(&a->a7mpcore),
sc->irqmap[ASPEED_DEV_PCIE0]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcie[0].rc), 0, irq);
mmio_mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->pcie[0].rc), 1);
memory_region_init_alias(&s->pcie_mmio_alias[0], OBJECT(&s->pcie[0].rc),
"aspeed.pcie-mmio", mmio_mr,
sc->memmap[ASPEED_DEV_PCIE_MMIO1],
0x10000000);
memory_region_add_subregion(s->memory,
sc->memmap[ASPEED_DEV_PCIE_MMIO1],
&s->pcie_mmio_alias[0]);
return true;
}
static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
{
int i;
@ -438,6 +507,11 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
sysbus_connect_irq(SYS_BUS_DEVICE(&s->peci), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_PECI));
/* PCIe Root Complex (RC) */
if (!aspeed_soc_ast2600_pcie_realize(dev, errp)) {
return;
}
/* FMC, The number of CS is set at the board level */
object_property_set_link(OBJECT(&s->fmc), "dram", OBJECT(s->dram_mr),
&error_abort);

View file

@ -56,7 +56,7 @@ struct Ast2700FCState {
#define AST2700FC_FMC_MODEL "w25q01jvq"
#define AST2700FC_SPI_MODEL "w25q512jv"
static void ast2700fc_ca35_init(MachineState *machine)
static bool ast2700fc_ca35_init(MachineState *machine, Error **errp)
{
Ast2700FCState *s = AST2700A1FC(machine);
AspeedSoCState *soc;
@ -71,22 +71,15 @@ static void ast2700fc_ca35_init(MachineState *machine)
memory_region_add_subregion(get_system_memory(), 0, &s->ca35_memory);
if (!memory_region_init_ram(&s->ca35_dram, OBJECT(&s->ca35), "ca35-dram",
AST2700FC_BMC_RAM_SIZE, &error_abort)) {
return;
}
if (!object_property_set_link(OBJECT(&s->ca35), "memory",
OBJECT(&s->ca35_memory),
&error_abort)) {
return;
};
if (!object_property_set_link(OBJECT(&s->ca35), "dram",
OBJECT(&s->ca35_dram), &error_abort)) {
return;
}
if (!object_property_set_int(OBJECT(&s->ca35), "ram-size",
AST2700FC_BMC_RAM_SIZE, &error_abort)) {
return;
AST2700FC_BMC_RAM_SIZE, errp)) {
return false;
}
object_property_set_link(OBJECT(&s->ca35), "memory",
OBJECT(&s->ca35_memory), &error_abort);
object_property_set_link(OBJECT(&s->ca35), "dram", OBJECT(&s->ca35_dram),
&error_abort);
object_property_set_int(OBJECT(&s->ca35), "ram-size",
AST2700FC_BMC_RAM_SIZE, &error_abort);
for (int i = 0; i < sc->macs_num; i++) {
if (!qemu_configure_nic_device(DEVICE(&soc->ftgmac100[i]),
@ -94,17 +87,13 @@ static void ast2700fc_ca35_init(MachineState *machine)
break;
}
}
if (!object_property_set_int(OBJECT(&s->ca35), "hw-strap1",
AST2700FC_HW_STRAP1, &error_abort)) {
return;
}
if (!object_property_set_int(OBJECT(&s->ca35), "hw-strap2",
AST2700FC_HW_STRAP2, &error_abort)) {
return;
}
object_property_set_int(OBJECT(&s->ca35), "hw-strap1",
AST2700FC_HW_STRAP1, &error_abort);
object_property_set_int(OBJECT(&s->ca35), "hw-strap2",
AST2700FC_HW_STRAP2, &error_abort);
aspeed_soc_uart_set_chr(soc, ASPEED_DEV_UART12, serial_hd(0));
if (!qdev_realize(DEVICE(&s->ca35), NULL, &error_abort)) {
return;
if (!qdev_realize(DEVICE(&s->ca35), NULL, errp)) {
return false;
}
/*
@ -119,9 +108,11 @@ static void ast2700fc_ca35_init(MachineState *machine)
ast2700fc_board_info.loader_start = sc->memmap[ASPEED_DEV_SDRAM];
arm_load_kernel(ARM_CPU(first_cpu), machine, &ast2700fc_board_info);
return true;
}
static void ast2700fc_ssp_init(MachineState *machine)
static bool ast2700fc_ssp_init(MachineState *machine, Error **errp)
{
AspeedSoCState *soc;
Ast2700FCState *s = AST2700A1FC(machine);
@ -133,19 +124,19 @@ static void ast2700fc_ssp_init(MachineState *machine)
UINT64_MAX);
qdev_connect_clock_in(DEVICE(&s->ssp), "sysclk", s->ssp_sysclk);
if (!object_property_set_link(OBJECT(&s->ssp), "memory",
OBJECT(&s->ssp_memory), &error_abort)) {
return;
}
object_property_set_link(OBJECT(&s->ssp), "memory",
OBJECT(&s->ssp_memory), &error_abort);
soc = ASPEED_SOC(&s->ssp);
aspeed_soc_uart_set_chr(soc, ASPEED_DEV_UART4, serial_hd(1));
if (!qdev_realize(DEVICE(&s->ssp), NULL, &error_abort)) {
return;
if (!qdev_realize(DEVICE(&s->ssp), NULL, errp)) {
return false;
}
return true;
}
static void ast2700fc_tsp_init(MachineState *machine)
static bool ast2700fc_tsp_init(MachineState *machine, Error **errp)
{
AspeedSoCState *soc;
Ast2700FCState *s = AST2700A1FC(machine);
@ -157,23 +148,23 @@ static void ast2700fc_tsp_init(MachineState *machine)
UINT64_MAX);
qdev_connect_clock_in(DEVICE(&s->tsp), "sysclk", s->tsp_sysclk);
if (!object_property_set_link(OBJECT(&s->tsp), "memory",
OBJECT(&s->tsp_memory), &error_abort)) {
return;
}
object_property_set_link(OBJECT(&s->tsp), "memory",
OBJECT(&s->tsp_memory), &error_abort);
soc = ASPEED_SOC(&s->tsp);
aspeed_soc_uart_set_chr(soc, ASPEED_DEV_UART7, serial_hd(2));
if (!qdev_realize(DEVICE(&s->tsp), NULL, &error_abort)) {
return;
if (!qdev_realize(DEVICE(&s->tsp), NULL, errp)) {
return false;
}
return true;
}
static void ast2700fc_init(MachineState *machine)
{
ast2700fc_ca35_init(machine);
ast2700fc_ssp_init(machine);
ast2700fc_tsp_init(machine);
ast2700fc_ca35_init(machine, &error_abort);
ast2700fc_ssp_init(machine, &error_abort);
ast2700fc_tsp_init(machine, &error_abort);
}
static void ast2700fc_class_init(ObjectClass *oc, const void *data)

View file

@ -38,6 +38,8 @@ static const hwaddr aspeed_soc_ast2700_memmap[] = {
[ASPEED_DEV_EHCI2] = 0x12063000,
[ASPEED_DEV_HACE] = 0x12070000,
[ASPEED_DEV_EMMC] = 0x12090000,
[ASPEED_DEV_PCIE0] = 0x120E0000,
[ASPEED_DEV_PCIE1] = 0x120F0000,
[ASPEED_DEV_INTC] = 0x12100000,
[ASPEED_GIC_DIST] = 0x12200000,
[ASPEED_GIC_REDIST] = 0x12280000,
@ -45,6 +47,8 @@ static const hwaddr aspeed_soc_ast2700_memmap[] = {
[ASPEED_DEV_SCU] = 0x12C02000,
[ASPEED_DEV_RTC] = 0x12C0F000,
[ASPEED_DEV_TIMER1] = 0x12C10000,
[ASPEED_DEV_PCIE_PHY0] = 0x12C15000,
[ASPEED_DEV_PCIE_PHY1] = 0x12C15800,
[ASPEED_DEV_SLI] = 0x12C17000,
[ASPEED_DEV_UART4] = 0x12C1A000,
[ASPEED_DEV_IOMEM1] = 0x14000000,
@ -59,6 +63,7 @@ static const hwaddr aspeed_soc_ast2700_memmap[] = {
[ASPEED_DEV_ETH2] = 0x14060000,
[ASPEED_DEV_ETH3] = 0x14070000,
[ASPEED_DEV_SDHCI] = 0x14080000,
[ASPEED_DEV_PCIE2] = 0x140D0000,
[ASPEED_DEV_EHCI3] = 0x14121000,
[ASPEED_DEV_EHCI4] = 0x14123000,
[ASPEED_DEV_ADC] = 0x14C00000,
@ -66,6 +71,7 @@ static const hwaddr aspeed_soc_ast2700_memmap[] = {
[ASPEED_DEV_GPIO] = 0x14C0B000,
[ASPEED_DEV_I2C] = 0x14C0F000,
[ASPEED_DEV_INTCIO] = 0x14C18000,
[ASPEED_DEV_PCIE_PHY2] = 0x14C1C000,
[ASPEED_DEV_SLIIO] = 0x14C1E000,
[ASPEED_DEV_VUART] = 0x14C30000,
[ASPEED_DEV_UART0] = 0x14C33000,
@ -81,6 +87,9 @@ static const hwaddr aspeed_soc_ast2700_memmap[] = {
[ASPEED_DEV_UART11] = 0x14C33A00,
[ASPEED_DEV_UART12] = 0x14C33B00,
[ASPEED_DEV_WDT] = 0x14C37000,
[ASPEED_DEV_PCIE_MMIO0] = 0x60000000,
[ASPEED_DEV_PCIE_MMIO1] = 0x80000000,
[ASPEED_DEV_PCIE_MMIO2] = 0xA0000000,
[ASPEED_DEV_SPI_BOOT] = 0x100000000,
[ASPEED_DEV_LTPI] = 0x300000000,
[ASPEED_DEV_SDRAM] = 0x400000000,
@ -156,6 +165,8 @@ static const int aspeed_soc_ast2700a1_irqmap[] = {
[ASPEED_DEV_DP] = 28,
[ASPEED_DEV_EHCI1] = 33,
[ASPEED_DEV_EHCI2] = 37,
[ASPEED_DEV_PCIE0] = 56,
[ASPEED_DEV_PCIE1] = 57,
[ASPEED_DEV_LPC] = 192,
[ASPEED_DEV_IBT] = 192,
[ASPEED_DEV_KCS] = 192,
@ -166,6 +177,7 @@ static const int aspeed_soc_ast2700a1_irqmap[] = {
[ASPEED_DEV_WDT] = 195,
[ASPEED_DEV_PWM] = 195,
[ASPEED_DEV_I3C] = 195,
[ASPEED_DEV_PCIE2] = 196,
[ASPEED_DEV_UART0] = 196,
[ASPEED_DEV_UART1] = 196,
[ASPEED_DEV_UART2] = 196,
@ -233,6 +245,7 @@ static const int ast2700_gic132_gic196_intcmap[] = {
[ASPEED_DEV_UART12] = 18,
[ASPEED_DEV_EHCI3] = 28,
[ASPEED_DEV_EHCI4] = 29,
[ASPEED_DEV_PCIE2] = 31,
};
/* GICINT 133 */
@ -519,6 +532,17 @@ static void aspeed_soc_ast2700_init(Object *obj)
snprintf(typename, sizeof(typename), "aspeed.hace-%s", socname);
object_initialize_child(obj, "hace", &s->hace, typename);
for (i = 0; i < sc->pcie_num; i++) {
snprintf(typename, sizeof(typename), "aspeed.pcie-phy-%s", socname);
object_initialize_child(obj, "pcie-phy[*]", &s->pcie_phy[i], typename);
object_property_set_int(OBJECT(&s->pcie_phy[i]), "id", i, &error_abort);
snprintf(typename, sizeof(typename), "aspeed.pcie-cfg-%s", socname);
object_initialize_child(obj, "pcie-cfg[*]", &s->pcie[i], typename);
object_property_set_int(OBJECT(&s->pcie[i]), "id", i, &error_abort);
}
object_initialize_child(obj, "dpmcu", &s->dpmcu,
TYPE_UNIMPLEMENTED_DEVICE);
object_initialize_child(obj, "ltpi", &s->ltpi,
@ -610,6 +634,49 @@ static bool aspeed_soc_ast2700_gic_realize(DeviceState *dev, Error **errp)
return true;
}
static bool aspeed_soc_ast2700_pcie_realize(DeviceState *dev, Error **errp)
{
AspeedSoCState *s = ASPEED_SOC(dev);
AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
MemoryRegion *mmio_mr = NULL;
char name[64];
qemu_irq irq;
int i;
for (i = 0; i < sc->pcie_num; i++) {
if (!sysbus_realize(SYS_BUS_DEVICE(&s->pcie_phy[i]), errp)) {
return false;
}
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->pcie_phy[i]), 0,
sc->memmap[ASPEED_DEV_PCIE_PHY0 + i]);
object_property_set_int(OBJECT(&s->pcie[i]), "dram-base",
sc->memmap[ASPEED_DEV_SDRAM],
&error_abort);
object_property_set_link(OBJECT(&s->pcie[i]), "dram",
OBJECT(s->dram_mr), &error_abort);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->pcie[i]), errp)) {
return false;
}
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->pcie[i]), 0,
sc->memmap[ASPEED_DEV_PCIE0 + i]);
irq = aspeed_soc_get_irq(s, ASPEED_DEV_PCIE0 + i);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcie[i].rc), 0, irq);
mmio_mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->pcie[i].rc), 1);
snprintf(name, sizeof(name), "aspeed.pcie-mmio.%d", i);
memory_region_init_alias(&s->pcie_mmio_alias[i], OBJECT(&s->pcie[i].rc),
name, mmio_mr,
sc->memmap[ASPEED_DEV_PCIE_MMIO0 + i],
0x20000000);
memory_region_add_subregion(s->memory,
sc->memmap[ASPEED_DEV_PCIE_MMIO0 + i],
&s->pcie_mmio_alias[i]);
}
return true;
}
static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp)
{
int i;
@ -936,6 +1003,11 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp)
sysbus_connect_irq(SYS_BUS_DEVICE(&s->hace), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_HACE));
/* PCIe Root Complex (RC) */
if (!aspeed_soc_ast2700_pcie_realize(dev, errp)) {
return;
}
aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->dpmcu),
"aspeed.dpmcu",
sc->memmap[ASPEED_DEV_DPMCU],
@ -974,6 +1046,7 @@ static void aspeed_soc_ast2700a0_class_init(ObjectClass *oc, const void *data)
sc->valid_cpu_types = valid_cpu_types;
sc->silicon_rev = AST2700_A0_SILICON_REV;
sc->sram_size = 0x20000;
sc->pcie_num = 0;
sc->spis_num = 3;
sc->ehcis_num = 2;
sc->wdts_num = 8;
@ -1002,6 +1075,7 @@ static void aspeed_soc_ast2700a1_class_init(ObjectClass *oc, const void *data)
sc->valid_cpu_types = valid_cpu_types;
sc->silicon_rev = AST2700_A1_SILICON_REV;
sc->sram_size = 0x20000;
sc->pcie_num = 3;
sc->spis_num = 3;
sc->ehcis_num = 4;
sc->wdts_num = 8;

View file

@ -16,6 +16,10 @@
#include "hw/misc/unimp.h"
#include "hw/arm/aspeed_soc.h"
#include "hw/char/serial-mm.h"
#include "system/blockdev.h"
#include "system/block-backend.h"
#include "hw/loader.h"
#include "qemu/datadir.h"
const char *aspeed_soc_cpu_type(AspeedSoCClass *sc)
@ -124,6 +128,98 @@ void aspeed_mmio_map_unimplemented(AspeedSoCState *s, SysBusDevice *dev,
sysbus_mmio_get_region(dev, 0), -1000);
}
void aspeed_board_init_flashes(AspeedSMCState *s, const char *flashtype,
unsigned int count, int unit0)
{
int i;
if (!flashtype) {
return;
}
for (i = 0; i < count; ++i) {
DriveInfo *dinfo = drive_get(IF_MTD, 0, unit0 + i);
DeviceState *dev;
dev = qdev_new(flashtype);
if (dinfo) {
qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(dinfo));
}
qdev_prop_set_uint8(dev, "cs", i);
qdev_realize_and_unref(dev, BUS(s->spi), &error_fatal);
}
}
void aspeed_write_boot_rom(BlockBackend *blk, hwaddr addr, size_t rom_size,
Error **errp)
{
g_autofree void *storage = NULL;
int64_t size;
/*
* The block backend size should have already been 'validated' by
* the creation of the m25p80 object.
*/
size = blk_getlength(blk);
if (size <= 0) {
error_setg(errp, "failed to get flash size");
return;
}
if (rom_size > size) {
rom_size = size;
}
storage = g_malloc0(rom_size);
if (blk_pread(blk, 0, rom_size, storage, 0) < 0) {
error_setg(errp, "failed to read the initial flash content");
return;
}
rom_add_blob_fixed("aspeed.boot_rom", storage, rom_size, addr);
}
/*
* Create a ROM and copy the flash contents at the expected address
* (0x0). Boots faster than execute-in-place.
*/
void aspeed_install_boot_rom(AspeedSoCState *soc, BlockBackend *blk,
MemoryRegion *boot_rom, uint64_t rom_size)
{
AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(soc);
memory_region_init_rom(boot_rom, NULL, "aspeed.boot_rom", rom_size,
&error_abort);
memory_region_add_subregion_overlap(&soc->spi_boot_container, 0,
boot_rom, 1);
aspeed_write_boot_rom(blk, sc->memmap[ASPEED_DEV_SPI_BOOT], rom_size,
&error_abort);
}
/*
* This function locates the vbootrom image file specified via the command line
* using the -bios option. It loads the specified image into the vbootrom
* memory region and handles errors if the file cannot be found or loaded.
*/
void aspeed_load_vbootrom(AspeedSoCState *soc, const char *bios_name,
Error **errp)
{
g_autofree char *filename = NULL;
int ret;
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
if (!filename) {
error_setg(errp, "Could not find vbootrom image '%s'", bios_name);
return;
}
ret = load_image_mr(filename, &soc->vbootrom);
if (ret < 0) {
error_setg(errp, "Failed to load vbootrom image '%s'", bios_name);
return;
}
}
static void aspeed_soc_realize(DeviceState *dev, Error **errp)
{
AspeedSoCState *s = ASPEED_SOC(dev);

View file

@ -15,9 +15,14 @@
#include "hw/misc/aspeed_sbc.h"
#include "qapi/error.h"
#include "migration/vmstate.h"
#include "trace.h"
#define R_PROT (0x000 / 4)
#define R_CMD (0x004 / 4)
#define R_ADDR (0x010 / 4)
#define R_STATUS (0x014 / 4)
#define R_CAMP1 (0x020 / 4)
#define R_CAMP2 (0x024 / 4)
#define R_QSR (0x040 / 4)
/* R_STATUS */
@ -41,6 +46,20 @@
#define QSR_RSA_MASK (0x3 << 12)
#define QSR_HASH_MASK (0x3 << 10)
#define OTP_MEMORY_SIZE 0x4000
/* OTP command */
#define SBC_OTP_CMD_READ 0x23b1e361
#define SBC_OTP_CMD_WRITE 0x23b1e362
#define SBC_OTP_CMD_PROG 0x23b1e364
#define OTP_DATA_DWORD_COUNT (0x800)
#define OTP_TOTAL_DWORD_COUNT (0x1000)
/* Voltage mode */
#define MODE_REGISTER (0x1000)
#define MODE_REGISTER_A (0x3000)
#define MODE_REGISTER_B (0x5000)
static uint64_t aspeed_sbc_read(void *opaque, hwaddr addr, unsigned int size)
{
AspeedSBCState *s = ASPEED_SBC(opaque);
@ -57,6 +76,142 @@ static uint64_t aspeed_sbc_read(void *opaque, hwaddr addr, unsigned int size)
return s->regs[addr];
}
static bool aspeed_sbc_otp_read(AspeedSBCState *s,
uint32_t otp_addr)
{
MemTxResult ret;
AspeedOTPState *otp = &s->otp;
uint32_t value, otp_offset;
bool is_data = false;
if (otp_addr < OTP_DATA_DWORD_COUNT) {
is_data = true;
} else if (otp_addr >= OTP_TOTAL_DWORD_COUNT) {
qemu_log_mask(LOG_GUEST_ERROR,
"Invalid OTP addr 0x%x\n",
otp_addr);
return false;
}
otp_offset = otp_addr << 2;
ret = address_space_read(&otp->as, otp_offset, MEMTXATTRS_UNSPECIFIED,
&value, sizeof(value));
if (ret != MEMTX_OK) {
qemu_log_mask(LOG_GUEST_ERROR,
"Failed to read OTP memory, addr = %x\n",
otp_addr);
return false;
}
s->regs[R_CAMP1] = value;
trace_aspeed_sbc_otp_read(otp_addr, value);
if (is_data) {
ret = address_space_read(&otp->as, otp_offset + 4,
MEMTXATTRS_UNSPECIFIED,
&value, sizeof(value));
if (ret != MEMTX_OK) {
qemu_log_mask(LOG_GUEST_ERROR,
"Failed to read OTP memory, addr = %x\n",
otp_addr);
return false;
}
s->regs[R_CAMP2] = value;
trace_aspeed_sbc_otp_read(otp_addr + 1, value);
}
return true;
}
static bool mode_handler(uint32_t otp_addr)
{
switch (otp_addr) {
case MODE_REGISTER:
case MODE_REGISTER_A:
case MODE_REGISTER_B:
/* HW behavior, do nothing here */
return true;
default:
qemu_log_mask(LOG_GUEST_ERROR,
"Unsupported address 0x%x\n",
otp_addr);
return false;
}
}
static bool aspeed_sbc_otp_write(AspeedSBCState *s,
uint32_t otp_addr)
{
if (otp_addr == 0) {
trace_aspeed_sbc_ignore_cmd(otp_addr);
return true;
} else {
if (mode_handler(otp_addr) == false) {
return false;
}
}
return true;
}
static bool aspeed_sbc_otp_prog(AspeedSBCState *s,
uint32_t otp_addr)
{
MemTxResult ret;
AspeedOTPState *otp = &s->otp;
uint32_t value = s->regs[R_CAMP1];
ret = address_space_write(&otp->as, otp_addr, MEMTXATTRS_UNSPECIFIED,
&value, sizeof(value));
if (ret != MEMTX_OK) {
qemu_log_mask(LOG_GUEST_ERROR,
"Failed to write OTP memory, addr = %x\n",
otp_addr);
return false;
}
trace_aspeed_sbc_otp_prog(otp_addr, value);
return true;
}
static void aspeed_sbc_handle_command(void *opaque, uint32_t cmd)
{
AspeedSBCState *s = ASPEED_SBC(opaque);
AspeedSBCClass *sc = ASPEED_SBC_GET_CLASS(opaque);
bool ret = false;
uint32_t otp_addr;
if (!sc->has_otp) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: OTP memory is not supported\n",
__func__);
return;
}
s->regs[R_STATUS] &= ~(OTP_MEM_IDLE | OTP_IDLE);
otp_addr = s->regs[R_ADDR];
switch (cmd) {
case SBC_OTP_CMD_READ:
ret = aspeed_sbc_otp_read(s, otp_addr);
break;
case SBC_OTP_CMD_WRITE:
ret = aspeed_sbc_otp_write(s, otp_addr);
break;
case SBC_OTP_CMD_PROG:
ret = aspeed_sbc_otp_prog(s, otp_addr);
break;
default:
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Unknown command 0x%x\n",
__func__, cmd);
break;
}
trace_aspeed_sbc_handle_cmd(cmd, otp_addr, ret);
s->regs[R_STATUS] |= (OTP_MEM_IDLE | OTP_IDLE);
}
static void aspeed_sbc_write(void *opaque, hwaddr addr, uint64_t data,
unsigned int size)
{
@ -78,6 +233,9 @@ static void aspeed_sbc_write(void *opaque, hwaddr addr, uint64_t data,
"%s: write to read only register 0x%" HWADDR_PRIx "\n",
__func__, addr << 2);
return;
case R_CMD:
aspeed_sbc_handle_command(opaque, data);
return;
default:
break;
}
@ -115,10 +273,30 @@ static void aspeed_sbc_reset(DeviceState *dev)
s->regs[R_QSR] = s->signing_settings;
}
static void aspeed_sbc_instance_init(Object *obj)
{
AspeedSBCClass *sc = ASPEED_SBC_GET_CLASS(obj);
AspeedSBCState *s = ASPEED_SBC(obj);
if (sc->has_otp) {
object_initialize_child(OBJECT(s), "otp", &s->otp,
TYPE_ASPEED_OTP);
}
}
static void aspeed_sbc_realize(DeviceState *dev, Error **errp)
{
AspeedSBCState *s = ASPEED_SBC(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
AspeedSBCClass *sc = ASPEED_SBC_GET_CLASS(dev);
if (sc->has_otp) {
object_property_set_int(OBJECT(&s->otp), "size",
OTP_MEMORY_SIZE, &error_abort);
if (!qdev_realize(DEVICE(&s->otp), NULL, errp)) {
return;
}
}
memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_sbc_ops, s,
TYPE_ASPEED_SBC, 0x1000);
@ -155,6 +333,7 @@ static const TypeInfo aspeed_sbc_info = {
.name = TYPE_ASPEED_SBC,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(AspeedSBCState),
.instance_init = aspeed_sbc_instance_init,
.class_init = aspeed_sbc_class_init,
.class_size = sizeof(AspeedSBCClass)
};
@ -162,8 +341,10 @@ static const TypeInfo aspeed_sbc_info = {
static void aspeed_ast2600_sbc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedSBCClass *sc = ASPEED_SBC_CLASS(klass);
dc->desc = "AST2600 Secure Boot Controller";
sc->has_otp = true;
}
static const TypeInfo aspeed_ast2600_sbc_info = {
@ -172,9 +353,25 @@ static const TypeInfo aspeed_ast2600_sbc_info = {
.class_init = aspeed_ast2600_sbc_class_init,
};
static void aspeed_ast10x0_sbc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedSBCClass *sc = ASPEED_SBC_CLASS(klass);
dc->desc = "AST10X0 Secure Boot Controller";
sc->has_otp = true;
}
static const TypeInfo aspeed_ast10x0_sbc_info = {
.name = TYPE_ASPEED_AST10X0_SBC,
.parent = TYPE_ASPEED_SBC,
.class_init = aspeed_ast10x0_sbc_class_init,
};
static void aspeed_sbc_register_types(void)
{
type_register_static(&aspeed_ast2600_sbc_info);
type_register_static(&aspeed_ast10x0_sbc_info);
type_register_static(&aspeed_sbc_info);
}

View file

@ -90,6 +90,12 @@ slavio_sysctrl_mem_readl(uint32_t ret) "Read system control 0x%08x"
slavio_led_mem_writew(uint32_t val) "Write diagnostic LED 0x%04x"
slavio_led_mem_readw(uint32_t ret) "Read diagnostic LED 0x%04x"
# aspeed_sbc.c
aspeed_sbc_ignore_cmd(uint32_t cmd) "Ignoring command 0x%" PRIx32
aspeed_sbc_handle_cmd(uint32_t cmd, uint32_t addr, bool ret) "Handling command 0x%" PRIx32 " for OTP addr 0x%" PRIx32 " Result: %d"
aspeed_sbc_otp_read(uint32_t addr, uint32_t value) "OTP Memory read: addr 0x%" PRIx32 " value 0x%" PRIx32
aspeed_sbc_otp_prog(uint32_t addr, uint32_t value) "OTP Memory write: addr 0x%" PRIx32 " value 0x%" PRIx32
# aspeed_scu.c
aspeed_scu_write(uint64_t offset, unsigned size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
aspeed_scu_read(uint64_t offset, unsigned size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32

190
hw/nvram/aspeed_otp.c Normal file
View file

@ -0,0 +1,190 @@
/*
* ASPEED OTP (One-Time Programmable) memory
*
* Copyright (C) 2025 Aspeed
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "qapi/error.h"
#include "system/block-backend.h"
#include "hw/qdev-properties.h"
#include "hw/nvram/aspeed_otp.h"
#include "hw/nvram/trace.h"
static uint64_t aspeed_otp_read(void *opaque, hwaddr offset, unsigned size)
{
AspeedOTPState *s = opaque;
uint64_t val = 0;
memcpy(&val, s->storage + offset, size);
return val;
}
static bool valid_program_data(uint32_t otp_addr,
uint32_t value, uint32_t prog_bit)
{
uint32_t programmed_bits, has_programmable_bits;
bool is_odd = otp_addr & 1;
/*
* prog_bit uses 0s to indicate target bits to program:
* - if OTP word is even-indexed, programmed bits flip 0->1
* - if odd, bits flip 1->0
* Bit programming is one-way only and irreversible.
*/
if (is_odd) {
programmed_bits = ~value & prog_bit;
} else {
programmed_bits = value & (~prog_bit);
}
/* If any bit can be programmed, accept the request */
has_programmable_bits = value ^ (~prog_bit);
if (programmed_bits) {
trace_aspeed_otp_prog_conflict(otp_addr, programmed_bits);
for (int i = 0; i < 32; ++i) {
if (programmed_bits & (1U << i)) {
trace_aspeed_otp_prog_bit(i);
}
}
}
return has_programmable_bits != 0;
}
static bool program_otpmem_data(void *opaque, uint32_t otp_addr,
uint32_t prog_bit, uint32_t *value)
{
AspeedOTPState *s = opaque;
bool is_odd = otp_addr & 1;
uint32_t otp_offset = otp_addr << 2;
memcpy(value, s->storage + otp_offset, sizeof(uint32_t));
if (!valid_program_data(otp_addr, *value, prog_bit)) {
return false;
}
if (is_odd) {
*value &= ~prog_bit;
} else {
*value |= ~prog_bit;
}
return true;
}
static void aspeed_otp_write(void *opaque, hwaddr otp_addr,
uint64_t val, unsigned size)
{
AspeedOTPState *s = opaque;
uint32_t otp_offset, value;
if (!program_otpmem_data(s, otp_addr, val, &value)) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Failed to program data, value = %x, bit = %"PRIx64"\n",
__func__, value, val);
return;
}
otp_offset = otp_addr << 2;
memcpy(s->storage + otp_offset, &value, size);
if (s->blk) {
if (blk_pwrite(s->blk, otp_offset, size, &value, 0) < 0) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Failed to write %x to %x\n",
__func__, value, otp_offset);
return;
}
}
trace_aspeed_otp_prog(otp_offset, val, value);
}
static bool aspeed_otp_init_storage(AspeedOTPState *s, Error **errp)
{
uint32_t *p;
int i, num;
uint64_t perm;
if (s->blk) {
perm = BLK_PERM_CONSISTENT_READ |
(blk_supports_write_perm(s->blk) ? BLK_PERM_WRITE : 0);
if (blk_set_perm(s->blk, perm, BLK_PERM_ALL, errp) < 0) {
return false;
}
if (blk_pread(s->blk, 0, s->size, s->storage, 0) < 0) {
error_setg(errp, "Failed to read the initial flash content");
return false;
}
} else {
num = s->size / sizeof(uint32_t);
p = (uint32_t *)s->storage;
for (i = 0; i < num; i++) {
p[i] = (i % 2 == 0) ? 0x00000000 : 0xFFFFFFFF;
}
}
return true;
}
static const MemoryRegionOps aspeed_otp_ops = {
.read = aspeed_otp_read,
.write = aspeed_otp_write,
.endianness = DEVICE_LITTLE_ENDIAN,
.valid.min_access_size = 1,
.valid.max_access_size = 4,
.valid.unaligned = true,
.impl.unaligned = true
};
static void aspeed_otp_realize(DeviceState *dev, Error **errp)
{
AspeedOTPState *s = ASPEED_OTP(dev);
if (s->size == 0) {
error_setg(errp, "aspeed.otp: 'size' property must be set");
return;
}
s->storage = blk_blockalign(s->blk, s->size);
if (!aspeed_otp_init_storage(s, errp)) {
return;
}
memory_region_init_io(&s->mmio, OBJECT(dev), &aspeed_otp_ops,
s, "aspeed.otp", s->size);
address_space_init(&s->as, &s->mmio, NULL);
}
static const Property aspeed_otp_properties[] = {
DEFINE_PROP_UINT64("size", AspeedOTPState, size, 0),
DEFINE_PROP_DRIVE("drive", AspeedOTPState, blk),
};
static void aspeed_otp_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = aspeed_otp_realize;
device_class_set_props(dc, aspeed_otp_properties);
}
static const TypeInfo aspeed_otp_info = {
.name = TYPE_ASPEED_OTP,
.parent = TYPE_DEVICE,
.instance_size = sizeof(AspeedOTPState),
.class_init = aspeed_otp_class_init,
};
static void aspeed_otp_register_types(void)
{
type_register_static(&aspeed_otp_info);
}
type_init(aspeed_otp_register_types)

View file

@ -19,3 +19,7 @@ system_ss.add(when: 'CONFIG_XLNX_BBRAM', if_true: files('xlnx-bbram.c'))
specific_ss.add(when: 'CONFIG_PSERIES', if_true: files('spapr_nvram.c'))
specific_ss.add(when: 'CONFIG_ACPI', if_true: files('fw_cfg-acpi.c'))
system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files(
'aspeed_otp.c',
))

View file

@ -1,5 +1,10 @@
# See docs/devel/tracing.rst for syntax documentation.
# aspeed_otp.c
aspeed_otp_prog(uint32_t addr, uint32_t prog_value, uint32_t value) "OTP Memory program: addr 0x%" PRIx32 " prog_value 0x%" PRIx32 " value 0x%" PRIx32
aspeed_otp_prog_conflict(uint32_t addr, uint32_t bits) "Conflict at addr=0x%x, bits=0x%08x"
aspeed_otp_prog_bit(int bit) "Programmed bit %d"
# ds1225y.c
nvram_read(uint32_t addr, uint32_t ret) "read addr %d: 0x%02x"
nvram_write(uint32_t addr, uint32_t old, uint32_t val) "write addr %d: 0x%02x -> 0x%02x"

View file

@ -46,6 +46,10 @@ config PCI_I440FX
select PCI
select PAM
config PCI_EXPRESS_ASPEED
bool
select PCI_EXPRESS
config PCI_EXPRESS_Q35
bool
select PCI_EXPRESS

1015
hw/pci-host/aspeed_pcie.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -2,6 +2,7 @@ pci_ss = ss.source_set()
pci_ss.add(when: 'CONFIG_PAM', if_true: files('pam.c'))
pci_ss.add(when: 'CONFIG_PCI_BONITO', if_true: files('bonito.c'))
pci_ss.add(when: 'CONFIG_GT64120', if_true: files('gt64120.c'))
pci_ss.add(when: 'CONFIG_PCI_EXPRESS_ASPEED', if_true: files('aspeed_pcie.c'))
pci_ss.add(when: 'CONFIG_PCI_EXPRESS_DESIGNWARE', if_true: files('designware.c'))
pci_ss.add(when: 'CONFIG_PCI_EXPRESS_GENERIC_BRIDGE', if_true: files('gpex.c'))
pci_ss.add(when: ['CONFIG_PCI_EXPRESS_GENERIC_BRIDGE', 'CONFIG_ACPI'], if_true: files('gpex-acpi.c'))

View file

@ -1,5 +1,16 @@
# See docs/devel/tracing.rst for syntax documentation.
# aspeed_pcie.c
aspeed_pcie_rc_intx_set_irq(uint32_t id, int num, int level) "%d: num %d set IRQ leve %d"
aspeed_pcie_rc_msi_notify(uint32_t id, uint64_t addr, uint64_t data) "%d: 0x%" PRIx64 " data 0x%" PRIx64
aspeed_pcie_rc_msi_set_irq(uint32_t id, uint64_t unm, int level) "%d: num 0x%" PRIx64 " set IRQ level %d"
aspeed_pcie_rc_msi_clear_irq(uint32_t id, int level) "%d: clear IRQ level %d"
aspeed_pcie_cfg_read(uint32_t id, uint64_t addr, uint32_t value) "%d: addr 0x%" PRIx64 " value 0x%" PRIx32
aspeed_pcie_cfg_write(uint32_t id, uint64_t addr, uint32_t value) "%d: addr 0x%" PRIx64 " value 0x%" PRIx32
aspeed_pcie_cfg_rw(uint32_t id, const char *dir, uint8_t bus, uint8_t devfn, uint64_t addr, uint64_t data) "%d: %s bus:0x%x devfn:0x%x addr 0x%" PRIx64 " data 0x%" PRIx64
aspeed_pcie_phy_read(uint32_t id, uint64_t addr, uint32_t value) "%d: addr 0x%" PRIx64 " value 0x%" PRIx32
aspeed_pcie_phy_write(uint32_t id, uint64_t addr, uint32_t value) "%d: addr 0x%" PRIx64 " value 0x%" PRIx32
# bonito.c
bonito_spciconf_small_access(uint64_t addr, unsigned size) "PCI config address is smaller then 32-bit, addr: 0x%"PRIx64", size: %u"

View file

@ -37,11 +37,14 @@
#include "qom/object.h"
#include "hw/misc/aspeed_lpc.h"
#include "hw/misc/unimp.h"
#include "hw/pci-host/aspeed_pcie.h"
#include "hw/misc/aspeed_peci.h"
#include "hw/fsi/aspeed_apb2opb.h"
#include "hw/char/serial-mm.h"
#include "hw/intc/arm_gicv3.h"
#define VBOOTROM_FILE_NAME "ast27x0_bootrom.bin"
#define ASPEED_SPIS_NUM 3
#define ASPEED_EHCIS_NUM 4
#define ASPEED_WDTS_NUM 8
@ -49,6 +52,7 @@
#define ASPEED_MACS_NUM 4
#define ASPEED_UARTS_NUM 13
#define ASPEED_JTAG_NUM 2
#define ASPEED_PCIE_NUM 3
struct AspeedSoCState {
DeviceState parent;
@ -60,6 +64,7 @@ struct AspeedSoCState {
MemoryRegion spi_boot_container;
MemoryRegion spi_boot;
MemoryRegion vbootrom;
MemoryRegion pcie_mmio_alias[ASPEED_PCIE_NUM];
AddressSpace dram_as;
AspeedRtcState rtc;
AspeedTimerCtrlState timerctrl;
@ -87,6 +92,8 @@ struct AspeedSoCState {
AspeedSDHCIState sdhci;
AspeedSDHCIState emmc;
AspeedLPCState lpc;
AspeedPCIECfgState pcie[ASPEED_PCIE_NUM];
AspeedPCIEPhyState pcie_phy[ASPEED_PCIE_NUM];
AspeedPECIState peci;
SerialMM uart[ASPEED_UARTS_NUM];
Clock *sysclk;
@ -181,6 +188,7 @@ struct AspeedSoCClass {
uint32_t silicon_rev;
uint64_t sram_size;
uint64_t secsram_size;
int pcie_num;
int spis_num;
int ehcis_num;
int wdts_num;
@ -254,6 +262,15 @@ enum {
ASPEED_DEV_LPC,
ASPEED_DEV_IBT,
ASPEED_DEV_I2C,
ASPEED_DEV_PCIE0,
ASPEED_DEV_PCIE1,
ASPEED_DEV_PCIE2,
ASPEED_DEV_PCIE_PHY0,
ASPEED_DEV_PCIE_PHY1,
ASPEED_DEV_PCIE_PHY2,
ASPEED_DEV_PCIE_MMIO0,
ASPEED_DEV_PCIE_MMIO1,
ASPEED_DEV_PCIE_MMIO2,
ASPEED_DEV_PECI,
ASPEED_DEV_ETH1,
ASPEED_DEV_ETH2,
@ -297,6 +314,12 @@ void aspeed_mmio_map_unimplemented(AspeedSoCState *s, SysBusDevice *dev,
uint64_t size);
void aspeed_board_init_flashes(AspeedSMCState *s, const char *flashtype,
unsigned int count, int unit0);
void aspeed_write_boot_rom(BlockBackend *blk, hwaddr addr, size_t rom_size,
Error **errp);
void aspeed_install_boot_rom(AspeedSoCState *soc, BlockBackend *blk,
MemoryRegion *boot_rom, uint64_t rom_size);
void aspeed_load_vbootrom(AspeedSoCState *soc, const char *bios_name,
Error **errp);
static inline int aspeed_uart_index(int uart_dev)
{

View file

@ -10,9 +10,11 @@
#define ASPEED_SBC_H
#include "hw/sysbus.h"
#include "hw/nvram/aspeed_otp.h"
#define TYPE_ASPEED_SBC "aspeed.sbc"
#define TYPE_ASPEED_AST2600_SBC TYPE_ASPEED_SBC "-ast2600"
#define TYPE_ASPEED_AST10X0_SBC TYPE_ASPEED_SBC "-ast10x0"
OBJECT_DECLARE_TYPE(AspeedSBCState, AspeedSBCClass, ASPEED_SBC)
#define ASPEED_SBC_NR_REGS (0x93c >> 2)
@ -36,10 +38,14 @@ struct AspeedSBCState {
MemoryRegion iomem;
uint32_t regs[ASPEED_SBC_NR_REGS];
AspeedOTPState otp;
};
struct AspeedSBCClass {
SysBusDeviceClass parent_class;
bool has_otp;
};
#endif /* ASPEED_SBC_H */

View file

@ -0,0 +1,33 @@
/*
* ASPEED OTP (One-Time Programmable) memory
*
* Copyright (C) 2025 Aspeed
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef ASPEED_OTP_H
#define ASPEED_OTP_H
#include "system/memory.h"
#include "hw/block/block.h"
#include "system/address-spaces.h"
#define TYPE_ASPEED_OTP "aspeed-otp"
OBJECT_DECLARE_SIMPLE_TYPE(AspeedOTPState, ASPEED_OTP)
typedef struct AspeedOTPState {
DeviceState parent_obj;
BlockBackend *blk;
uint64_t size;
AddressSpace as;
MemoryRegion mmio;
uint8_t *storage;
} AspeedOTPState;
#endif /* ASPEED_OTP_H */

View file

@ -0,0 +1,137 @@
/*
* ASPEED PCIe Host Controller
*
* Copyright (C) 2025 ASPEED Technology Inc.
* Copyright (c) 2022 Cédric Le Goater <clg@kaod.org>
*
* Authors:
* Cédric Le Goater <clg@kaod.org>
* Jamin Lin <jamin_lin@aspeedtech.com>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
* Based on previous work from Cédric Le Goater.
* Modifications extend support for the ASPEED AST2600 and AST2700 platforms.
*/
#ifndef ASPEED_PCIE_H
#define ASPEED_PCIE_H
#include "hw/sysbus.h"
#include "hw/pci/pci_bridge.h"
#include "hw/pci/pcie_host.h"
#include "hw/pci/pcie_port.h"
#include "qom/object.h"
typedef struct AspeedPCIECfgTxDesc {
uint32_t desc0;
uint32_t desc1;
uint32_t desc2;
uint32_t desc3;
uint32_t wdata;
uint32_t rdata_reg;
} AspeedPCIECfgTxDesc;
typedef struct AspeedPCIERcRegs {
uint32_t int_en_reg;
uint32_t int_sts_reg;
uint32_t msi_sts0_reg;
uint32_t msi_sts1_reg;
} AspeedPCIERcRegs;
typedef struct AspeedPCIERegMap {
AspeedPCIERcRegs rc;
} AspeedPCIERegMap;
#define TYPE_ASPEED_PCIE_ROOT_PORT "aspeed.pcie-root-port"
OBJECT_DECLARE_SIMPLE_TYPE(AspeedPCIERootPortState, ASPEED_PCIE_ROOT_PORT)
typedef struct AspeedPCIERootPortState {
PCIESlot parent_obj;
} AspeedPCIERootPortState;
#define TYPE_ASPEED_PCIE_ROOT_DEVICE "aspeed.pcie-root-device"
OBJECT_DECLARE_SIMPLE_TYPE(AspeedPCIERootDeviceState, ASPEED_PCIE_ROOT_DEVICE);
struct AspeedPCIERootDeviceState {
PCIBridge parent_obj;
};
#define TYPE_ASPEED_PCIE_RC "aspeed.pcie-rc"
OBJECT_DECLARE_SIMPLE_TYPE(AspeedPCIERcState, ASPEED_PCIE_RC);
struct AspeedPCIERcState {
PCIExpressHost parent_obj;
MemoryRegion iommu_root;
AddressSpace iommu_as;
MemoryRegion dram_alias;
MemoryRegion *dram_mr;
MemoryRegion mmio_window;
MemoryRegion msi_window;
MemoryRegion io_window;
MemoryRegion mmio;
MemoryRegion io;
uint64_t dram_base;
uint32_t msi_addr;
uint32_t rp_addr;
uint32_t bus_nr;
char name[16];
bool has_rd;
qemu_irq irq;
AspeedPCIERootDeviceState root_device;
AspeedPCIERootPortState root_port;
};
/* Bridge between AHB bus and PCIe RC. */
#define TYPE_ASPEED_PCIE_CFG "aspeed.pcie-cfg"
#define TYPE_ASPEED_2700_PCIE_CFG TYPE_ASPEED_PCIE_CFG "-ast2700"
OBJECT_DECLARE_TYPE(AspeedPCIECfgState, AspeedPCIECfgClass, ASPEED_PCIE_CFG);
struct AspeedPCIECfgState {
SysBusDevice parent_obj;
MemoryRegion mmio;
uint32_t *regs;
uint32_t id;
const AspeedPCIERcRegs *rc_regs;
AspeedPCIERcState rc;
uint32_t tlpn_fifo[3];
uint32_t tlpn_idx;
};
struct AspeedPCIECfgClass {
SysBusDeviceClass parent_class;
const AspeedPCIERegMap *reg_map;
const MemoryRegionOps *reg_ops;
uint32_t rc_msi_addr;
uint32_t rc_rp_addr;
uint64_t rc_bus_nr;
uint64_t nr_regs;
bool rc_has_rd;
};
#define TYPE_ASPEED_PCIE_PHY "aspeed.pcie-phy"
#define TYPE_ASPEED_2700_PCIE_PHY TYPE_ASPEED_PCIE_PHY "-ast2700"
OBJECT_DECLARE_TYPE(AspeedPCIEPhyState, AspeedPCIEPhyClass, ASPEED_PCIE_PHY);
struct AspeedPCIEPhyState {
SysBusDevice parent_obj;
MemoryRegion mmio;
uint32_t *regs;
uint32_t id;
};
struct AspeedPCIEPhyClass {
SysBusDeviceClass parent_class;
uint64_t nr_regs;
};
#endif /* ASPEED_PCIE_H */

View file

@ -291,4 +291,6 @@
#define PCI_VENDOR_ID_NVIDIA 0x10de
#define PCI_VENDOR_ID_ASPEED 0x1A03
#endif

View file

@ -115,8 +115,8 @@ class AST2x00MachineSDK(QemuSystemTest):
self.do_test_aarch64_aspeed_sdk_start(
self.scratch_file(name, 'image-bmc'))
def test_aarch64_ast2700_evb_sdk_v09_06(self):
self.set_machine('ast2700-evb')
def test_aarch64_ast2700a0_evb_sdk_v09_06(self):
self.set_machine('ast2700a0-evb')
self.archive_extract(self.ASSET_SDK_V906_AST2700)
self.start_ast2700_test('ast2700-a0-default')

View file

@ -7,17 +7,18 @@
# SPDX-License-Identifier: GPL-2.0-or-later
from qemu_test import LinuxKernelTest, Asset
from aspeed import AspeedTest
from qemu_test import exec_command_and_wait_for_pattern
class AST1030Machine(LinuxKernelTest):
class AST1030Machine(AspeedTest):
ASSET_ZEPHYR_3_02 = Asset(
('https://github.com/AspeedTech-BMC'
'/zephyr/releases/download/v00.03.02/ast1030-evb-demo.zip'),
'1ec83caab3ddd5d09481772801be7210e222cb015ce22ec6fffb8a76956dcd4f')
def test_ast1030_zephyros_3_02(self):
def test_arm_ast1030_zephyros_3_02(self):
self.set_machine('ast1030-evb')
kernel_name = "ast1030-evb-demo-3/zephyr.elf"
@ -36,7 +37,7 @@ class AST1030Machine(LinuxKernelTest):
'/zephyr/releases/download/v00.01.07/ast1030-evb-demo.zip'),
'ad52e27959746988afaed8429bf4e12ab988c05c4d07c9d90e13ec6f7be4574c')
def test_ast1030_zephyros_1_07(self):
def test_arm_ast1030_zephyros_1_07(self):
self.set_machine('ast1030-evb')
kernel_name = "ast1030-evb-demo/zephyr.bin"
@ -68,6 +69,21 @@ class AST1030Machine(LinuxKernelTest):
'kernel uptime',
]: exec_command_and_wait_for_pattern(self, shell_cmd, "uart:~$")
def test_arm_ast1030_otp_blockdev_device(self):
self.vm.set_machine("ast1030-evb")
kernel_name = "ast1030-evb-demo-3/zephyr.elf"
kernel_file = self.archive_extract(self.ASSET_ZEPHYR_3_02, member=kernel_name)
otp_img = self.generate_otpmem_image()
self.vm.set_console()
self.vm.add_args(
"-kernel", kernel_file,
"-blockdev", f"driver=file,filename={otp_img},node-name=otp",
"-global", "aspeed-otp.drive=otp",
)
self.vm.launch()
self.wait_for_console_pattern("Booting Zephyr OS")
if __name__ == '__main__':
LinuxKernelTest.main()
AspeedTest.main()

View file

@ -101,8 +101,26 @@ class AST2600Machine(AspeedTest):
'https://github.com/AspeedTech-BMC/openbmc/releases/download/v09.07/ast2600-default-obmc.tar.gz',
'cb6c08595bcbba1672ce716b068ba4e48eda1ed9abe78a07b30392ba2278feba')
def do_ast2600_pcie_test(self):
exec_command_and_wait_for_pattern(self,
'lspci -s 80:00.0',
'80:00.0 Host bridge: '
'ASPEED Technology, Inc. Device 2600')
exec_command_and_wait_for_pattern(self,
'lspci -s 80:08.0',
'80:08.0 PCI bridge: '
'ASPEED Technology, Inc. AST1150 PCI-to-PCI Bridge')
exec_command_and_wait_for_pattern(self,
'lspci -s 81:00.0',
'81:00.0 Ethernet controller: '
'Intel Corporation 82574L Gigabit Network Connection')
exec_command_and_wait_for_pattern(self,
'ip addr show dev eth4',
'inet 10.0.2.15/24')
def test_arm_ast2600_evb_sdk(self):
self.set_machine('ast2600-evb')
self.require_netdev('user')
self.archive_extract(self.ASSET_SDK_V907_AST2600)
@ -110,6 +128,8 @@ class AST2600Machine(AspeedTest):
'tmp105,bus=aspeed.i2c.bus.5,address=0x4d,id=tmp-test')
self.vm.add_args('-device',
'ds1338,bus=aspeed.i2c.bus.5,address=0x32')
self.vm.add_args('-device', 'e1000e,netdev=net1,bus=pcie.0')
self.vm.add_args('-netdev', 'user,id=net1')
self.do_test_arm_aspeed_sdk_start(
self.scratch_file("ast2600-default", "image-bmc"))
@ -135,6 +155,22 @@ class AST2600Machine(AspeedTest):
year = time.strftime("%Y")
exec_command_and_wait_for_pattern(self,
'/sbin/hwclock -f /dev/rtc1', year)
self.do_ast2600_pcie_test()
def test_arm_ast2600_otp_blockdev_device(self):
self.vm.set_machine("ast2600-evb")
image_path = self.archive_extract(self.ASSET_SDK_V907_AST2600)
otp_img = self.generate_otpmem_image()
self.vm.set_console()
self.vm.add_args(
"-blockdev", f"driver=file,filename={otp_img},node-name=otp",
"-global", "aspeed-otp.drive=otp",
)
self.do_test_arm_aspeed_sdk_start(
self.scratch_file("ast2600-default", "image-bmc"))
self.wait_for_console_pattern("ast2600-default login:")
if __name__ == '__main__':
AspeedTest.main()

View file

@ -61,3 +61,11 @@ class AspeedTest(LinuxKernelTest):
self.wait_for_console_pattern('U-Boot 2019.04')
self.wait_for_console_pattern('## Loading kernel from FIT Image')
self.wait_for_console_pattern('Starting kernel ...')
def generate_otpmem_image(self):
path = self.scratch_file("otpmem.img")
pattern = b'\x00\x00\x00\x00\xff\xff\xff\xff' * (16 * 1024 // 8)
with open(path, "wb") as f:
f.write(pattern)
return path