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:
commit
85a3fd1c4c
26 changed files with 2019 additions and 153 deletions
|
|
@ -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``)
|
||||
==================================================================
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
107
hw/arm/aspeed.c
107
hw/arm/aspeed.c
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
190
hw/nvram/aspeed_otp.c
Normal 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)
|
||||
|
|
@ -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',
|
||||
))
|
||||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
1015
hw/pci-host/aspeed_pcie.c
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -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'))
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
33
include/hw/nvram/aspeed_otp.h
Normal file
33
include/hw/nvram/aspeed_otp.h
Normal 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 */
|
||||
137
include/hw/pci-host/aspeed_pcie.h
Normal file
137
include/hw/pci-host/aspeed_pcie.h
Normal 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 */
|
||||
|
|
@ -291,4 +291,6 @@
|
|||
|
||||
#define PCI_VENDOR_ID_NVIDIA 0x10de
|
||||
|
||||
#define PCI_VENDOR_ID_ASPEED 0x1A03
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue