aspeed queue:

* Removed tacoma-bmc machine
 * Added support for SDHCI on AST2700 SoC
 * Improved functional tests
 * Extended SMC qtest to all Aspeed SoCs
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEoPZlSPBIlev+awtgUaNDx8/77KEFAmdZMTQACgkQUaNDx8/7
 7KE9dhAAw9xNULQ7KG9udSNqYPRGP2w8teO4b9YOfRlJlSJuCInbeLjg1Hw3b/bZ
 rEtnwjl18f+mpmHzvasQthN4vUtcR1UwrW6SvmAjAQV8iNw059ugxWdxV9VR72hc
 1AlzsW/Hea8s448INTEUvEjosYeLRRxZQyiJt9Lf5IkU/6yLj98YssKKvRqPpkxP
 Ens7PapgGPqA7cPnPYofRn2WINtHNnvX2FGlWTnCoPVp85VJzjJVFcK14kBych2U
 fmNZAY7pPTBkwwqR/qoPOyqBBCLeu3Jimk7hR8VbBbfwMT/Zg3RO7TJfwJex9TEs
 PIViRuM8krEppL6fmJlpDTatU2t0ffQY1SSVRWCDxJDDRpQN7iDei3vuzXOfLVAe
 lLSXS5Q1f+sO6JzbqkYSufh5V7zR5De8rk4j5WszC3cko2godTZm3qyqUxEaQGcx
 kjG58R+a7qLLeNMcPed5qgGjYeCPmhHay80E3faXKOezktSIM5z5b822ZPZfw3oG
 gTddZ4hdTg0BxtEjSv19qqnJW0Hs+NZJQuyu34QS82dZqPeZ22dmfULtf9uQ/3oV
 A/jKfTncl3sW1otfLABj6/RPVH/Sr7IM70XBjlc1+p9Ci7Es17er8umFOAyek9WL
 pE/Lq23MnAPBUsPKOJRdDFClTGwdnemXJoymwY/NZS4SgV3GcD8=
 =BiCq
 -----END PGP SIGNATURE-----

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

aspeed queue:

* Removed tacoma-bmc machine
* Added support for SDHCI on AST2700 SoC
* Improved functional tests
* Extended SMC qtest to all Aspeed SoCs

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEEoPZlSPBIlev+awtgUaNDx8/77KEFAmdZMTQACgkQUaNDx8/7
# 7KE9dhAAw9xNULQ7KG9udSNqYPRGP2w8teO4b9YOfRlJlSJuCInbeLjg1Hw3b/bZ
# rEtnwjl18f+mpmHzvasQthN4vUtcR1UwrW6SvmAjAQV8iNw059ugxWdxV9VR72hc
# 1AlzsW/Hea8s448INTEUvEjosYeLRRxZQyiJt9Lf5IkU/6yLj98YssKKvRqPpkxP
# Ens7PapgGPqA7cPnPYofRn2WINtHNnvX2FGlWTnCoPVp85VJzjJVFcK14kBych2U
# fmNZAY7pPTBkwwqR/qoPOyqBBCLeu3Jimk7hR8VbBbfwMT/Zg3RO7TJfwJex9TEs
# PIViRuM8krEppL6fmJlpDTatU2t0ffQY1SSVRWCDxJDDRpQN7iDei3vuzXOfLVAe
# lLSXS5Q1f+sO6JzbqkYSufh5V7zR5De8rk4j5WszC3cko2godTZm3qyqUxEaQGcx
# kjG58R+a7qLLeNMcPed5qgGjYeCPmhHay80E3faXKOezktSIM5z5b822ZPZfw3oG
# gTddZ4hdTg0BxtEjSv19qqnJW0Hs+NZJQuyu34QS82dZqPeZ22dmfULtf9uQ/3oV
# A/jKfTncl3sW1otfLABj6/RPVH/Sr7IM70XBjlc1+p9Ci7Es17er8umFOAyek9WL
# pE/Lq23MnAPBUsPKOJRdDFClTGwdnemXJoymwY/NZS4SgV3GcD8=
# =BiCq
# -----END PGP SIGNATURE-----
# gpg: Signature made Wed 11 Dec 2024 06:29:08 GMT
# 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]
# Primary key fingerprint: A0F6 6548 F048 95EB FE6B  0B60 51A3 43C7 CFFB ECA1

* tag 'pull-aspeed-20241211' of https://github.com/legoater/qemu: (24 commits)
  test/qtest/ast2700-smc-test: Support to test AST2700
  test/qtest: Introduce a new aspeed-smc-utils.c to place common testcases
  test/qtest/aspeed_smc-test: Support write page command with QPI mode
  test/qtest/aspeed_smc-test: Support to test AST1030
  test/qtest/aspeed_smc-test: Support to test AST2600
  test/qtest/aspeed_smc-test: Support to test AST2500
  test/qtest/aspeed_smc-test: Introducing a "page_addr" data field
  test/qtest/aspeed_smc-test: Support to test all CE pins
  test/qtest/aspeed_smc-test: Introduce a new TestData to test different BMC SOCs
  test/qtest/aspeed_smc-test: Move testcases to test_palmetto_bmc function
  tests/functional: Move debian boot test from avocado
  tests/functional: Introduce a specific test for rainier-bmc machine
  tests/functional: Introduce a specific test for ast2600 SoC
  tests/functional: Introduce a specific test for ast2500 SoC
  tests/functional: Introduce a specific test for romulus-bmc machine
  tests/functional: Introduce a specific test for palmetto-bmc machine
  tests/functional: Introduce a specific test for ast1030 SoC
  aspeed/soc: Support eMMC for AST2700
  aspeed/soc: Support SDHCI for AST2700
  hw/sd/aspeed_sdhci: Add AST2700 Support
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2024-12-11 15:16:47 +00:00
commit a5ba0a7e4e
24 changed files with 1623 additions and 1025 deletions

View file

@ -263,14 +263,6 @@ images are not available, OpenWRT dropped support in 2019, U-Boot in
2017, Linux also is dropping support in 2024. It is time to let go of 2017, Linux also is dropping support in 2024. It is time to let go of
this ancient hardware and focus on newer CPUs and platforms. this ancient hardware and focus on newer CPUs and platforms.
Arm ``tacoma-bmc`` machine (since 9.1)
''''''''''''''''''''''''''''''''''''''''
The ``tacoma-bmc`` machine was a board including an AST2600 SoC based
BMC and a witherspoon like OpenPOWER system. It was used for bring up
of the AST2600 SoC in labs. It can be easily replaced by the
``rainier-bmc`` machine which is a real product.
Big-Endian variants of MicroBlaze ``petalogix-ml605`` and ``xlnx-zynqmp-pmu`` machines (since 9.2) Big-Endian variants of MicroBlaze ``petalogix-ml605`` and ``xlnx-zynqmp-pmu`` machines (since 9.2)
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

View file

@ -1019,6 +1019,16 @@ Aspeed ``swift-bmc`` machine (removed in 7.0)
This machine was removed because it was unused. Alternative AST2500 based This machine was removed because it was unused. Alternative AST2500 based
OpenPOWER machines are ``witherspoon-bmc`` and ``romulus-bmc``. OpenPOWER machines are ``witherspoon-bmc`` and ``romulus-bmc``.
Aspeed ``tacoma-bmc`` machine (removed in 10.0)
'''''''''''''''''''''''''''''''''''''''''''''''
The ``tacoma-bmc`` machine was removed because it didn't bring much
compared to the ``rainier-bmc`` machine. Also, the ``tacoma-bmc`` was
a board used for bring up of the AST2600 SoC that never left the
labs. It can be easily replaced by the ``rainier-bmc`` machine, which
was the actual final product, or by the ``ast2600-evb`` with some
tweaks.
ppc ``taihu`` machine (removed in 7.2) ppc ``taihu`` machine (removed in 7.2)
''''''''''''''''''''''''''''''''''''''''''''' '''''''''''''''''''''''''''''''''''''''''''''

View file

@ -32,7 +32,6 @@ AST2500 SoC based machines :
AST2600 SoC based machines : AST2600 SoC based machines :
- ``ast2600-evb`` Aspeed AST2600 Evaluation board (Cortex-A7) - ``ast2600-evb`` Aspeed AST2600 Evaluation board (Cortex-A7)
- ``tacoma-bmc`` OpenPOWER Witherspoon POWER9 AST2600 BMC
- ``rainier-bmc`` IBM Rainier POWER10 BMC - ``rainier-bmc`` IBM Rainier POWER10 BMC
- ``fuji-bmc`` Facebook Fuji BMC - ``fuji-bmc`` Facebook Fuji BMC
- ``bletchley-bmc`` Facebook Bletchley BMC - ``bletchley-bmc`` Facebook Bletchley BMC

View file

@ -185,10 +185,6 @@ struct AspeedMachineState {
#define AST2700_EVB_HW_STRAP2 0x00000003 #define AST2700_EVB_HW_STRAP2 0x00000003
#endif #endif
/* Tacoma hardware value */
#define TACOMA_BMC_HW_STRAP1 0x00000000
#define TACOMA_BMC_HW_STRAP2 0x00000040
/* Rainier hardware value: (QEMU prototype) */ /* Rainier hardware value: (QEMU prototype) */
#define RAINIER_BMC_HW_STRAP1 (0x00422016 | SCU_AST2600_HW_STRAP_BOOT_SRC_EMMC) #define RAINIER_BMC_HW_STRAP1 (0x00422016 | SCU_AST2600_HW_STRAP_BOOT_SRC_EMMC)
#define RAINIER_BMC_HW_STRAP2 0x80000848 #define RAINIER_BMC_HW_STRAP2 0x80000848
@ -1425,26 +1421,6 @@ static void aspeed_machine_ast2600_evb_class_init(ObjectClass *oc, void *data)
aspeed_machine_ast2600_class_emmc_init(oc); aspeed_machine_ast2600_class_emmc_init(oc);
}; };
static void aspeed_machine_tacoma_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
mc->desc = "OpenPOWER Tacoma BMC (Cortex-A7)";
amc->soc_name = "ast2600-a3";
amc->hw_strap1 = TACOMA_BMC_HW_STRAP1;
amc->hw_strap2 = TACOMA_BMC_HW_STRAP2;
amc->fmc_model = "mx66l1g45g";
amc->spi_model = "mx66l1g45g";
amc->num_cs = 2;
amc->macs_mask = ASPEED_MAC2_ON;
amc->i2c_init = witherspoon_bmc_i2c_init; /* Same board layout */
mc->default_ram_size = 1 * GiB;
aspeed_machine_class_init_cpus_defaults(mc);
mc->deprecation_reason = "Please use the similar 'rainier-bmc' machine";
};
static void aspeed_machine_g220a_class_init(ObjectClass *oc, void *data) static void aspeed_machine_g220a_class_init(ObjectClass *oc, void *data)
{ {
MachineClass *mc = MACHINE_CLASS(oc); MachineClass *mc = MACHINE_CLASS(oc);
@ -1766,10 +1742,6 @@ static const TypeInfo aspeed_machine_types[] = {
.name = MACHINE_TYPE_NAME("yosemitev2-bmc"), .name = MACHINE_TYPE_NAME("yosemitev2-bmc"),
.parent = TYPE_ASPEED_MACHINE, .parent = TYPE_ASPEED_MACHINE,
.class_init = aspeed_machine_yosemitev2_class_init, .class_init = aspeed_machine_yosemitev2_class_init,
}, {
.name = MACHINE_TYPE_NAME("tacoma-bmc"),
.parent = TYPE_ASPEED_MACHINE,
.class_init = aspeed_machine_tacoma_class_init,
}, { }, {
.name = MACHINE_TYPE_NAME("tiogapass-bmc"), .name = MACHINE_TYPE_NAME("tiogapass-bmc"),
.parent = TYPE_ASPEED_MACHINE, .parent = TYPE_ASPEED_MACHINE,

View file

@ -224,7 +224,8 @@ static void aspeed_ast2400_soc_init(Object *obj)
snprintf(typename, sizeof(typename), "aspeed.gpio-%s", socname); snprintf(typename, sizeof(typename), "aspeed.gpio-%s", socname);
object_initialize_child(obj, "gpio", &s->gpio, typename); object_initialize_child(obj, "gpio", &s->gpio, typename);
object_initialize_child(obj, "sdc", &s->sdhci, TYPE_ASPEED_SDHCI); snprintf(typename, sizeof(typename), "aspeed.sdhci-%s", socname);
object_initialize_child(obj, "sdc", &s->sdhci, typename);
object_property_set_int(OBJECT(&s->sdhci), "num-slots", 2, &error_abort); object_property_set_int(OBJECT(&s->sdhci), "num-slots", 2, &error_abort);

View file

@ -236,8 +236,8 @@ static void aspeed_soc_ast2600_init(Object *obj)
snprintf(typename, sizeof(typename), "aspeed.gpio-%s-1_8v", socname); snprintf(typename, sizeof(typename), "aspeed.gpio-%s-1_8v", socname);
object_initialize_child(obj, "gpio_1_8v", &s->gpio_1_8v, typename); object_initialize_child(obj, "gpio_1_8v", &s->gpio_1_8v, typename);
object_initialize_child(obj, "sd-controller", &s->sdhci, snprintf(typename, sizeof(typename), "aspeed.sdhci-%s", socname);
TYPE_ASPEED_SDHCI); object_initialize_child(obj, "sd-controller", &s->sdhci, typename);
object_property_set_int(OBJECT(&s->sdhci), "num-slots", 2, &error_abort); object_property_set_int(OBJECT(&s->sdhci), "num-slots", 2, &error_abort);
@ -247,8 +247,7 @@ static void aspeed_soc_ast2600_init(Object *obj)
&s->sdhci.slots[i], TYPE_SYSBUS_SDHCI); &s->sdhci.slots[i], TYPE_SYSBUS_SDHCI);
} }
object_initialize_child(obj, "emmc-controller", &s->emmc, object_initialize_child(obj, "emmc-controller", &s->emmc, typename);
TYPE_ASPEED_SDHCI);
object_property_set_int(OBJECT(&s->emmc), "num-slots", 1, &error_abort); object_property_set_int(OBJECT(&s->emmc), "num-slots", 1, &error_abort);
@ -541,7 +540,8 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), errp)) { if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), errp)) {
return; return;
} }
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->gpio), 0, sc->memmap[ASPEED_DEV_GPIO]); aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->gpio), 0,
sc->memmap[ASPEED_DEV_GPIO]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio), 0, sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_GPIO)); aspeed_soc_get_irq(s, ASPEED_DEV_GPIO));

View file

@ -65,6 +65,7 @@ static const hwaddr aspeed_soc_ast2700_memmap[] = {
[ASPEED_DEV_I2C] = 0x14C0F000, [ASPEED_DEV_I2C] = 0x14C0F000,
[ASPEED_DEV_GPIO] = 0x14C0B000, [ASPEED_DEV_GPIO] = 0x14C0B000,
[ASPEED_DEV_RTC] = 0x12C0F000, [ASPEED_DEV_RTC] = 0x12C0F000,
[ASPEED_DEV_SDHCI] = 0x14080000,
}; };
#define AST2700_MAX_IRQ 256 #define AST2700_MAX_IRQ 256
@ -113,6 +114,7 @@ static const int aspeed_soc_ast2700_irqmap[] = {
[ASPEED_DEV_KCS] = 128, [ASPEED_DEV_KCS] = 128,
[ASPEED_DEV_DP] = 28, [ASPEED_DEV_DP] = 28,
[ASPEED_DEV_I3C] = 131, [ASPEED_DEV_I3C] = 131,
[ASPEED_DEV_SDHCI] = 133,
}; };
/* GICINT 128 */ /* GICINT 128 */
@ -158,6 +160,7 @@ static const int aspeed_soc_ast2700_gic132_intcmap[] = {
/* GICINT 133 */ /* GICINT 133 */
static const int aspeed_soc_ast2700_gic133_intcmap[] = { static const int aspeed_soc_ast2700_gic133_intcmap[] = {
[ASPEED_DEV_SDHCI] = 1,
[ASPEED_DEV_PECI] = 4, [ASPEED_DEV_PECI] = 4,
}; };
@ -380,6 +383,20 @@ static void aspeed_soc_ast2700_init(Object *obj)
object_initialize_child(obj, "gpio", &s->gpio, typename); object_initialize_child(obj, "gpio", &s->gpio, typename);
object_initialize_child(obj, "rtc", &s->rtc, TYPE_ASPEED_RTC); object_initialize_child(obj, "rtc", &s->rtc, TYPE_ASPEED_RTC);
snprintf(typename, sizeof(typename), "aspeed.sdhci-%s", socname);
object_initialize_child(obj, "sd-controller", &s->sdhci, typename);
object_property_set_int(OBJECT(&s->sdhci), "num-slots", 1, &error_abort);
/* Init sd card slot class here so that they're under the correct parent */
object_initialize_child(obj, "sd-controller.sdhci",
&s->sdhci.slots[0], TYPE_SYSBUS_SDHCI);
object_initialize_child(obj, "emmc-controller", &s->emmc, typename);
object_property_set_int(OBJECT(&s->emmc), "num-slots", 1, &error_abort);
object_initialize_child(obj, "emmc-controller.sdhci", &s->emmc.slots[0],
TYPE_SYSBUS_SDHCI);
} }
/* /*
@ -681,6 +698,24 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp)
sysbus_connect_irq(SYS_BUS_DEVICE(&s->rtc), 0, sysbus_connect_irq(SYS_BUS_DEVICE(&s->rtc), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_RTC)); aspeed_soc_get_irq(s, ASPEED_DEV_RTC));
/* SDHCI */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->sdhci), errp)) {
return;
}
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sdhci), 0,
sc->memmap[ASPEED_DEV_SDHCI]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdhci), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_SDHCI));
/* eMMC */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->emmc), errp)) {
return;
}
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->emmc), 0,
sc->memmap[ASPEED_DEV_EMMC]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->emmc), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_EMMC));
create_unimplemented_device("ast2700.dpmcu", 0x11000000, 0x40000); create_unimplemented_device("ast2700.dpmcu", 0x11000000, 0x40000);
create_unimplemented_device("ast2700.iomem0", 0x12000000, 0x01000000); create_unimplemented_device("ast2700.iomem0", 0x12000000, 0x01000000);
create_unimplemented_device("ast2700.iomem1", 0x14000000, 0x01000000); create_unimplemented_device("ast2700.iomem1", 0x14000000, 0x01000000);

View file

@ -87,10 +87,12 @@ static void aspeed_sdhci_write(void *opaque, hwaddr addr, uint64_t val,
sdhci->regs[TO_REG(addr)] = (uint32_t)val & ~ASPEED_SDHCI_INFO_RESET; sdhci->regs[TO_REG(addr)] = (uint32_t)val & ~ASPEED_SDHCI_INFO_RESET;
break; break;
case ASPEED_SDHCI_SDIO_140: case ASPEED_SDHCI_SDIO_140:
sdhci->slots[0].capareg = deposit64(sdhci->slots[0].capareg, 0, 32, val); sdhci->slots[0].capareg = deposit64(sdhci->slots[0].capareg,
0, 32, val);
break; break;
case ASPEED_SDHCI_SDIO_144: case ASPEED_SDHCI_SDIO_144:
sdhci->slots[0].capareg = deposit64(sdhci->slots[0].capareg, 32, 32, val); sdhci->slots[0].capareg = deposit64(sdhci->slots[0].capareg,
32, 32, val);
break; break;
case ASPEED_SDHCI_SDIO_148: case ASPEED_SDHCI_SDIO_148:
sdhci->slots[0].maxcurr = deposit64(sdhci->slots[0].maxcurr, sdhci->slots[0].maxcurr = deposit64(sdhci->slots[0].maxcurr,
@ -146,6 +148,7 @@ static void aspeed_sdhci_realize(DeviceState *dev, Error **errp)
{ {
SysBusDevice *sbd = SYS_BUS_DEVICE(dev); SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
AspeedSDHCIState *sdhci = ASPEED_SDHCI(dev); AspeedSDHCIState *sdhci = ASPEED_SDHCI(dev);
AspeedSDHCIClass *asc = ASPEED_SDHCI_GET_CLASS(sdhci);
/* Create input irqs for the slots */ /* Create input irqs for the slots */
qdev_init_gpio_in_named_with_opaque(DEVICE(sbd), aspeed_sdhci_set_irq, qdev_init_gpio_in_named_with_opaque(DEVICE(sbd), aspeed_sdhci_set_irq,
@ -165,7 +168,7 @@ static void aspeed_sdhci_realize(DeviceState *dev, Error **errp)
} }
if (!object_property_set_uint(sdhci_slot, "capareg", if (!object_property_set_uint(sdhci_slot, "capareg",
ASPEED_SDHCI_CAPABILITIES, errp)) { asc->capareg, errp)) {
return; return;
} }
@ -216,12 +219,70 @@ static void aspeed_sdhci_class_init(ObjectClass *classp, void *data)
device_class_set_props(dc, aspeed_sdhci_properties); device_class_set_props(dc, aspeed_sdhci_properties);
} }
static void aspeed_2400_sdhci_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedSDHCIClass *asc = ASPEED_SDHCI_CLASS(klass);
dc->desc = "ASPEED 2400 SDHCI Controller";
asc->capareg = 0x0000000001e80080;
}
static void aspeed_2500_sdhci_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedSDHCIClass *asc = ASPEED_SDHCI_CLASS(klass);
dc->desc = "ASPEED 2500 SDHCI Controller";
asc->capareg = 0x0000000001e80080;
}
static void aspeed_2600_sdhci_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedSDHCIClass *asc = ASPEED_SDHCI_CLASS(klass);
dc->desc = "ASPEED 2600 SDHCI Controller";
asc->capareg = 0x0000000701f80080;
}
static void aspeed_2700_sdhci_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedSDHCIClass *asc = ASPEED_SDHCI_CLASS(klass);
dc->desc = "ASPEED 2700 SDHCI Controller";
asc->capareg = 0x0000000719f80080;
}
static const TypeInfo aspeed_sdhci_types[] = { static const TypeInfo aspeed_sdhci_types[] = {
{ {
.name = TYPE_ASPEED_SDHCI, .name = TYPE_ASPEED_SDHCI,
.parent = TYPE_SYS_BUS_DEVICE, .parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(AspeedSDHCIState), .instance_size = sizeof(AspeedSDHCIState),
.class_init = aspeed_sdhci_class_init, .class_init = aspeed_sdhci_class_init,
.class_size = sizeof(AspeedSDHCIClass),
.abstract = true,
},
{
.name = TYPE_ASPEED_2400_SDHCI,
.parent = TYPE_ASPEED_SDHCI,
.class_init = aspeed_2400_sdhci_class_init,
},
{
.name = TYPE_ASPEED_2500_SDHCI,
.parent = TYPE_ASPEED_SDHCI,
.class_init = aspeed_2500_sdhci_class_init,
},
{
.name = TYPE_ASPEED_2600_SDHCI,
.parent = TYPE_ASPEED_SDHCI,
.class_init = aspeed_2600_sdhci_class_init,
},
{
.name = TYPE_ASPEED_2700_SDHCI,
.parent = TYPE_ASPEED_SDHCI,
.class_init = aspeed_2700_sdhci_class_init,
}, },
}; };

View file

@ -13,9 +13,12 @@
#include "qom/object.h" #include "qom/object.h"
#define TYPE_ASPEED_SDHCI "aspeed.sdhci" #define TYPE_ASPEED_SDHCI "aspeed.sdhci"
OBJECT_DECLARE_SIMPLE_TYPE(AspeedSDHCIState, ASPEED_SDHCI) #define TYPE_ASPEED_2400_SDHCI TYPE_ASPEED_SDHCI "-ast2400"
#define TYPE_ASPEED_2500_SDHCI TYPE_ASPEED_SDHCI "-ast2500"
#define TYPE_ASPEED_2600_SDHCI TYPE_ASPEED_SDHCI "-ast2600"
#define TYPE_ASPEED_2700_SDHCI TYPE_ASPEED_SDHCI "-ast2700"
OBJECT_DECLARE_TYPE(AspeedSDHCIState, AspeedSDHCIClass, ASPEED_SDHCI)
#define ASPEED_SDHCI_CAPABILITIES 0x01E80080
#define ASPEED_SDHCI_NUM_SLOTS 2 #define ASPEED_SDHCI_NUM_SLOTS 2
#define ASPEED_SDHCI_NUM_REGS (ASPEED_SDHCI_REG_SIZE / sizeof(uint32_t)) #define ASPEED_SDHCI_NUM_REGS (ASPEED_SDHCI_REG_SIZE / sizeof(uint32_t))
#define ASPEED_SDHCI_REG_SIZE 0x100 #define ASPEED_SDHCI_REG_SIZE 0x100
@ -32,4 +35,10 @@ struct AspeedSDHCIState {
uint32_t regs[ASPEED_SDHCI_NUM_REGS]; uint32_t regs[ASPEED_SDHCI_NUM_REGS];
}; };
struct AspeedSDHCIClass {
SysBusDeviceClass parent_class;
uint64_t capareg;
};
#endif /* ASPEED_SDHCI_H */ #endif /* ASPEED_SDHCI_H */

View file

@ -470,29 +470,3 @@ class BootLinuxConsole(LinuxKernelTest):
self.wait_for_console_pattern('CPU1: thread -1, cpu 1, socket 0') self.wait_for_console_pattern('CPU1: thread -1, cpu 1, socket 0')
self.wait_for_console_pattern( self.wait_for_console_pattern(
'Give root password for system maintenance') 'Give root password for system maintenance')
def test_arm_ast2600_debian(self):
"""
:avocado: tags=arch:arm
:avocado: tags=machine:rainier-bmc
"""
deb_url = ('http://snapshot.debian.org/archive/debian/'
'20220606T211338Z/'
'pool/main/l/linux/'
'linux-image-5.17.0-2-armmp_5.17.6-1%2Bb1_armhf.deb')
deb_hash = '8acb2b4439faedc2f3ed4bdb2847ad4f6e0491f73debaeb7f660c8abe4dcdc0e'
deb_path = self.fetch_asset(deb_url, asset_hash=deb_hash,
algorithm='sha256')
kernel_path = self.extract_from_deb(deb_path, '/boot/vmlinuz-5.17.0-2-armmp')
dtb_path = self.extract_from_deb(deb_path,
'/usr/lib/linux-image-5.17.0-2-armmp/aspeed-bmc-ibm-rainier.dtb')
self.vm.set_console()
self.vm.add_args('-kernel', kernel_path,
'-dtb', dtb_path,
'-net', 'nic')
self.vm.launch()
self.wait_for_console_pattern("Booting Linux on physical CPU 0xf00")
self.wait_for_console_pattern("SMP: Total of 2 processors activated")
self.wait_for_console_pattern("No filesystem could mount root")

View file

@ -0,0 +1,56 @@
# Test class to boot aspeed machines
#
# SPDX-License-Identifier: GPL-2.0-or-later
from qemu_test import exec_command_and_wait_for_pattern
from qemu_test import LinuxKernelTest
class AspeedTest(LinuxKernelTest):
def do_test_arm_aspeed(self, machine, image):
self.set_machine(machine)
self.vm.set_console()
self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw',
'-net', 'nic', '-snapshot')
self.vm.launch()
self.wait_for_console_pattern("U-Boot 2016.07")
self.wait_for_console_pattern("## Loading kernel from FIT Image at 20080000")
self.wait_for_console_pattern("Starting kernel ...")
self.wait_for_console_pattern("Booting Linux on physical CPU 0x0")
self.wait_for_console_pattern(
"aspeed-smc 1e620000.spi: read control register: 203b0641")
self.wait_for_console_pattern("ftgmac100 1e660000.ethernet eth0: irq ")
self.wait_for_console_pattern("systemd[1]: Set hostname to")
def do_test_arm_aspeed_buildroot_start(self, image, cpu_id, pattern='Aspeed EVB'):
self.require_netdev('user')
self.vm.set_console()
self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw,read-only=true',
'-net', 'nic', '-net', 'user')
self.vm.launch()
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 ...')
self.wait_for_console_pattern('Booting Linux on physical CPU ' + cpu_id)
self.wait_for_console_pattern('lease of 10.0.2.15')
# the line before login:
self.wait_for_console_pattern(pattern)
exec_command_and_wait_for_pattern(self, 'root', 'Password:')
exec_command_and_wait_for_pattern(self, 'passw0rd', '#')
def do_test_arm_aspeed_buildroot_poweroff(self):
exec_command_and_wait_for_pattern(self, 'poweroff',
'reboot: System halted');
def do_test_arm_aspeed_sdk_start(self, image):
self.require_netdev('user')
self.vm.set_console()
self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw',
'-net', 'nic', '-net', 'user', '-snapshot')
self.vm.launch()
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 ...')

View file

@ -18,7 +18,11 @@ test_timeouts = {
'aarch64_tuxrun' : 240, 'aarch64_tuxrun' : 240,
'aarch64_virt' : 720, 'aarch64_virt' : 720,
'acpi_bits' : 420, 'acpi_bits' : 420,
'arm_aspeed' : 600, 'arm_aspeed_palmetto' : 120,
'arm_aspeed_romulus' : 120,
'arm_aspeed_ast2500' : 480,
'arm_aspeed_ast2600' : 720,
'arm_aspeed_rainier' : 240,
'arm_bpim2u' : 500, 'arm_bpim2u' : 500,
'arm_collie' : 180, 'arm_collie' : 180,
'arm_orangepi' : 540, 'arm_orangepi' : 540,
@ -65,7 +69,12 @@ tests_alpha_system_thorough = [
] ]
tests_arm_system_thorough = [ tests_arm_system_thorough = [
'arm_aspeed', 'arm_aspeed_ast1030',
'arm_aspeed_palmetto',
'arm_aspeed_romulus',
'arm_aspeed_ast2500',
'arm_aspeed_ast2600',
'arm_aspeed_rainier',
'arm_bpim2u', 'arm_bpim2u',
'arm_canona1100', 'arm_canona1100',
'arm_collie', 'arm_collie',

View file

@ -1,351 +0,0 @@
#!/usr/bin/env python3
#
# Functional test that boots the ASPEED SoCs with firmware
#
# Copyright (C) 2022 ASPEED Technology Inc
#
# SPDX-License-Identifier: GPL-2.0-or-later
import os
import time
import subprocess
import tempfile
from qemu_test import LinuxKernelTest, Asset
from qemu_test import exec_command_and_wait_for_pattern
from qemu_test import interrupt_interactive_console_until_pattern
from qemu_test import has_cmd
from qemu_test.utils import archive_extract
from zipfile import ZipFile
from unittest import skipUnless
class AST1030Machine(LinuxKernelTest):
ASSET_ZEPHYR_1_04 = Asset(
('https://github.com/AspeedTech-BMC'
'/zephyr/releases/download/v00.01.04/ast1030-evb-demo.zip'),
'4ac6210adcbc61294927918707c6762483fd844dde5e07f3ba834ad1f91434d3')
def test_ast1030_zephyros_1_04(self):
self.set_machine('ast1030-evb')
zip_file = self.ASSET_ZEPHYR_1_04.fetch()
kernel_name = "ast1030-evb-demo/zephyr.elf"
with ZipFile(zip_file, 'r') as zf:
zf.extract(kernel_name, path=self.workdir)
kernel_file = os.path.join(self.workdir, kernel_name)
self.vm.set_console()
self.vm.add_args('-kernel', kernel_file, '-nographic')
self.vm.launch()
self.wait_for_console_pattern("Booting Zephyr OS")
exec_command_and_wait_for_pattern(self, "help",
"Available commands")
ASSET_ZEPHYR_1_07 = Asset(
('https://github.com/AspeedTech-BMC'
'/zephyr/releases/download/v00.01.07/ast1030-evb-demo.zip'),
'ad52e27959746988afaed8429bf4e12ab988c05c4d07c9d90e13ec6f7be4574c')
def test_ast1030_zephyros_1_07(self):
self.set_machine('ast1030-evb')
zip_file = self.ASSET_ZEPHYR_1_07.fetch()
kernel_name = "ast1030-evb-demo/zephyr.bin"
with ZipFile(zip_file, 'r') as zf:
zf.extract(kernel_name, path=self.workdir)
kernel_file = os.path.join(self.workdir, kernel_name)
self.vm.set_console()
self.vm.add_args('-kernel', kernel_file, '-nographic')
self.vm.launch()
self.wait_for_console_pattern("Booting Zephyr OS")
for shell_cmd in [
'kernel stacks',
'otp info conf',
'otp info scu',
'hwinfo devid',
'crypto aes256_cbc_vault',
'random get',
'jtag JTAG1 sw_xfer high TMS',
'adc ADC0 resolution 12',
'adc ADC0 read 42',
'adc ADC1 read 69',
'i2c scan I2C_0',
'i3c attach I3C_0',
'hash test',
'kernel uptime',
'kernel reboot warm',
'kernel uptime',
'kernel reboot cold',
'kernel uptime',
]: exec_command_and_wait_for_pattern(self, shell_cmd, "uart:~$")
class AST2x00Machine(LinuxKernelTest):
def do_test_arm_aspeed(self, machine, image):
self.set_machine(machine)
self.vm.set_console()
self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw',
'-net', 'nic', '-snapshot')
self.vm.launch()
self.wait_for_console_pattern("U-Boot 2016.07")
self.wait_for_console_pattern("## Loading kernel from FIT Image at 20080000")
self.wait_for_console_pattern("Starting kernel ...")
self.wait_for_console_pattern("Booting Linux on physical CPU 0x0")
self.wait_for_console_pattern(
"aspeed-smc 1e620000.spi: read control register: 203b0641")
self.wait_for_console_pattern("ftgmac100 1e660000.ethernet eth0: irq ")
self.wait_for_console_pattern("systemd[1]: Set hostname to")
ASSET_PALMETTO_FLASH = Asset(
('https://github.com/openbmc/openbmc/releases/download/2.9.0/'
'obmc-phosphor-image-palmetto.static.mtd'),
'3e13bbbc28e424865dc42f35ad672b10f2e82cdb11846bb28fa625b48beafd0d');
def test_arm_ast2400_palmetto_openbmc_v2_9_0(self):
image_path = self.ASSET_PALMETTO_FLASH.fetch()
self.do_test_arm_aspeed('palmetto-bmc', image_path)
ASSET_ROMULUS_FLASH = Asset(
('https://github.com/openbmc/openbmc/releases/download/2.9.0/'
'obmc-phosphor-image-romulus.static.mtd'),
'820341076803f1955bc31e647a512c79f9add4f5233d0697678bab4604c7bb25')
def test_arm_ast2500_romulus_openbmc_v2_9_0(self):
image_path = self.ASSET_ROMULUS_FLASH.fetch()
self.do_test_arm_aspeed('romulus-bmc', image_path)
def do_test_arm_aspeed_buildroot_start(self, image, cpu_id, pattern='Aspeed EVB'):
self.require_netdev('user')
self.vm.set_console()
self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw,read-only=true',
'-net', 'nic', '-net', 'user')
self.vm.launch()
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 ...')
self.wait_for_console_pattern('Booting Linux on physical CPU ' + cpu_id)
self.wait_for_console_pattern('lease of 10.0.2.15')
# the line before login:
self.wait_for_console_pattern(pattern)
exec_command_and_wait_for_pattern(self, 'root', 'Password:')
exec_command_and_wait_for_pattern(self, 'passw0rd', '#')
def do_test_arm_aspeed_buildroot_poweroff(self):
exec_command_and_wait_for_pattern(self, 'poweroff',
'reboot: System halted');
ASSET_BR2_202311_AST2500_FLASH = Asset(
('https://github.com/legoater/qemu-aspeed-boot/raw/master/'
'images/ast2500-evb/buildroot-2023.11/flash.img'),
'c23db6160cf77d0258397eb2051162c8473a56c441417c52a91ba217186e715f')
def test_arm_ast2500_evb_buildroot(self):
self.set_machine('ast2500-evb')
image_path = self.ASSET_BR2_202311_AST2500_FLASH.fetch()
self.vm.add_args('-device',
'tmp105,bus=aspeed.i2c.bus.3,address=0x4d,id=tmp-test');
self.do_test_arm_aspeed_buildroot_start(image_path, '0x0',
'ast2500-evb login:')
exec_command_and_wait_for_pattern(self,
'echo lm75 0x4d > /sys/class/i2c-dev/i2c-3/device/new_device',
'i2c i2c-3: new_device: Instantiated device lm75 at 0x4d');
exec_command_and_wait_for_pattern(self,
'cat /sys/class/hwmon/hwmon1/temp1_input', '0')
self.vm.cmd('qom-set', path='/machine/peripheral/tmp-test',
property='temperature', value=18000);
exec_command_and_wait_for_pattern(self,
'cat /sys/class/hwmon/hwmon1/temp1_input', '18000')
self.do_test_arm_aspeed_buildroot_poweroff()
ASSET_BR2_202311_AST2600_FLASH = Asset(
('https://github.com/legoater/qemu-aspeed-boot/raw/master/'
'images/ast2600-evb/buildroot-2023.11/flash.img'),
'b62808daef48b438d0728ee07662290490ecfa65987bb91294cafb1bb7ad1a68')
def test_arm_ast2600_evb_buildroot(self):
self.set_machine('ast2600-evb')
image_path = self.ASSET_BR2_202311_AST2600_FLASH.fetch()
self.vm.add_args('-device',
'tmp105,bus=aspeed.i2c.bus.3,address=0x4d,id=tmp-test');
self.vm.add_args('-device',
'ds1338,bus=aspeed.i2c.bus.3,address=0x32');
self.vm.add_args('-device',
'i2c-echo,bus=aspeed.i2c.bus.3,address=0x42');
self.do_test_arm_aspeed_buildroot_start(image_path, '0xf00',
'ast2600-evb login:')
exec_command_and_wait_for_pattern(self,
'echo lm75 0x4d > /sys/class/i2c-dev/i2c-3/device/new_device',
'i2c i2c-3: new_device: Instantiated device lm75 at 0x4d');
exec_command_and_wait_for_pattern(self,
'cat /sys/class/hwmon/hwmon1/temp1_input', '0')
self.vm.cmd('qom-set', path='/machine/peripheral/tmp-test',
property='temperature', value=18000);
exec_command_and_wait_for_pattern(self,
'cat /sys/class/hwmon/hwmon1/temp1_input', '18000')
exec_command_and_wait_for_pattern(self,
'echo ds1307 0x32 > /sys/class/i2c-dev/i2c-3/device/new_device',
'i2c i2c-3: new_device: Instantiated device ds1307 at 0x32');
year = time.strftime("%Y")
exec_command_and_wait_for_pattern(self, 'hwclock -f /dev/rtc1', year);
exec_command_and_wait_for_pattern(self,
'echo slave-24c02 0x1064 > /sys/bus/i2c/devices/i2c-3/new_device',
'i2c i2c-3: new_device: Instantiated device slave-24c02 at 0x64');
exec_command_and_wait_for_pattern(self,
'i2cset -y 3 0x42 0x64 0x00 0xaa i', '#');
exec_command_and_wait_for_pattern(self,
'hexdump /sys/bus/i2c/devices/3-1064/slave-eeprom',
'0000000 ffaa ffff ffff ffff ffff ffff ffff ffff');
self.do_test_arm_aspeed_buildroot_poweroff()
ASSET_BR2_202302_AST2600_TPM_FLASH = Asset(
('https://github.com/legoater/qemu-aspeed-boot/raw/master/'
'images/ast2600-evb/buildroot-2023.02-tpm/flash.img'),
'a46009ae8a5403a0826d607215e731a8c68d27c14c41e55331706b8f9c7bd997')
@skipUnless(*has_cmd('swtpm'))
def test_arm_ast2600_evb_buildroot_tpm(self):
self.set_machine('ast2600-evb')
image_path = self.ASSET_BR2_202302_AST2600_TPM_FLASH.fetch()
tpmstate_dir = tempfile.TemporaryDirectory(prefix="qemu_")
socket = os.path.join(tpmstate_dir.name, 'swtpm-socket')
# We must put the TPM state dir in /tmp/, not the build dir,
# because some distros use AppArmor to lock down swtpm and
# restrict the set of locations it can access files in.
subprocess.run(['swtpm', 'socket', '-d', '--tpm2',
'--tpmstate', f'dir={tpmstate_dir.name}',
'--ctrl', f'type=unixio,path={socket}'])
self.vm.add_args('-chardev', f'socket,id=chrtpm,path={socket}')
self.vm.add_args('-tpmdev', 'emulator,id=tpm0,chardev=chrtpm')
self.vm.add_args('-device',
'tpm-tis-i2c,tpmdev=tpm0,bus=aspeed.i2c.bus.12,address=0x2e')
self.do_test_arm_aspeed_buildroot_start(image_path, '0xf00', 'Aspeed AST2600 EVB')
exec_command_and_wait_for_pattern(self,
'echo tpm_tis_i2c 0x2e > /sys/bus/i2c/devices/i2c-12/new_device',
'tpm_tis_i2c 12-002e: 2.0 TPM (device-id 0x1, rev-id 1)');
exec_command_and_wait_for_pattern(self,
'cat /sys/class/tpm/tpm0/pcr-sha256/0',
'B804724EA13F52A9072BA87FE8FDCC497DFC9DF9AA15B9088694639C431688E0');
self.do_test_arm_aspeed_buildroot_poweroff()
def do_test_arm_aspeed_sdk_start(self, image):
self.require_netdev('user')
self.vm.set_console()
self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw',
'-net', 'nic', '-net', 'user', '-snapshot')
self.vm.launch()
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 ...')
ASSET_SDK_V806_AST2500 = Asset(
'https://github.com/AspeedTech-BMC/openbmc/releases/download/v08.06/ast2500-default-obmc.tar.gz',
'e1755f3cadff69190438c688d52dd0f0d399b70a1e14b1d3d5540fc4851d38ca')
def test_arm_ast2500_evb_sdk(self):
self.set_machine('ast2500-evb')
image_path = self.ASSET_SDK_V806_AST2500.fetch()
archive_extract(image_path, self.workdir)
self.do_test_arm_aspeed_sdk_start(
self.workdir + '/ast2500-default/image-bmc')
self.wait_for_console_pattern('ast2500-default login:')
ASSET_SDK_V806_AST2600_A2 = Asset(
'https://github.com/AspeedTech-BMC/openbmc/releases/download/v08.06/ast2600-a2-obmc.tar.gz',
'9083506135f622d5e7351fcf7d4e1c7125cee5ba16141220c0ba88931f3681a4')
def test_arm_ast2600_evb_sdk(self):
self.set_machine('ast2600-evb')
image_path = self.ASSET_SDK_V806_AST2600_A2.fetch()
archive_extract(image_path, self.workdir)
self.vm.add_args('-device',
'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.do_test_arm_aspeed_sdk_start(
self.workdir + '/ast2600-a2/image-bmc')
self.wait_for_console_pattern('ast2600-a2 login:')
exec_command_and_wait_for_pattern(self, 'root', 'Password:')
exec_command_and_wait_for_pattern(self, '0penBmc', 'root@ast2600-a2:~#')
exec_command_and_wait_for_pattern(self,
'echo lm75 0x4d > /sys/class/i2c-dev/i2c-5/device/new_device',
'i2c i2c-5: new_device: Instantiated device lm75 at 0x4d');
exec_command_and_wait_for_pattern(self,
'cat /sys/class/hwmon/hwmon19/temp1_input', '0')
self.vm.cmd('qom-set', path='/machine/peripheral/tmp-test',
property='temperature', value=18000);
exec_command_and_wait_for_pattern(self,
'cat /sys/class/hwmon/hwmon19/temp1_input', '18000')
exec_command_and_wait_for_pattern(self,
'echo ds1307 0x32 > /sys/class/i2c-dev/i2c-5/device/new_device',
'i2c i2c-5: new_device: Instantiated device ds1307 at 0x32');
year = time.strftime("%Y")
exec_command_and_wait_for_pattern(self,
'/sbin/hwclock -f /dev/rtc1', year);
class AST2x00MachineMMC(LinuxKernelTest):
ASSET_RAINIER_EMMC = Asset(
('https://fileserver.linaro.org/s/B6pJTwWEkzSDi36/download/'
'mmc-p10bmc-20240617.qcow2'),
'd523fb478d2b84d5adc5658d08502bc64b1486955683814f89c6137518acd90b')
def test_arm_aspeed_emmc_boot(self):
self.set_machine('rainier-bmc')
self.require_netdev('user')
image_path = self.ASSET_RAINIER_EMMC.fetch()
self.vm.set_console()
self.vm.add_args('-drive',
'file=' + image_path + ',if=sd,id=sd2,index=2',
'-net', 'nic', '-net', 'user', '-snapshot')
self.vm.launch()
self.wait_for_console_pattern('U-Boot SPL 2019.04')
self.wait_for_console_pattern('Trying to boot from MMC1')
self.wait_for_console_pattern('U-Boot 2019.04')
self.wait_for_console_pattern('eMMC 2nd Boot')
self.wait_for_console_pattern('## Loading kernel from FIT Image')
self.wait_for_console_pattern('Starting kernel ...')
self.wait_for_console_pattern('Booting Linux on physical CPU 0xf00')
self.wait_for_console_pattern('mmcblk0: p1 p2 p3 p4 p5 p6 p7')
self.wait_for_console_pattern('IBM eBMC (OpenBMC for IBM Enterprise')
if __name__ == '__main__':
LinuxKernelTest.main()

View file

@ -0,0 +1,81 @@
#!/usr/bin/env python3
#
# Functional test that boots the ASPEED SoCs with firmware
#
# Copyright (C) 2022 ASPEED Technology Inc
#
# SPDX-License-Identifier: GPL-2.0-or-later
import os
from qemu_test import LinuxKernelTest, Asset
from qemu_test import exec_command_and_wait_for_pattern
from zipfile import ZipFile
class AST1030Machine(LinuxKernelTest):
ASSET_ZEPHYR_1_04 = Asset(
('https://github.com/AspeedTech-BMC'
'/zephyr/releases/download/v00.01.04/ast1030-evb-demo.zip'),
'4ac6210adcbc61294927918707c6762483fd844dde5e07f3ba834ad1f91434d3')
def test_ast1030_zephyros_1_04(self):
self.set_machine('ast1030-evb')
zip_file = self.ASSET_ZEPHYR_1_04.fetch()
kernel_name = "ast1030-evb-demo/zephyr.elf"
with ZipFile(zip_file, 'r') as zf:
zf.extract(kernel_name, path=self.workdir)
kernel_file = os.path.join(self.workdir, kernel_name)
self.vm.set_console()
self.vm.add_args('-kernel', kernel_file, '-nographic')
self.vm.launch()
self.wait_for_console_pattern("Booting Zephyr OS")
exec_command_and_wait_for_pattern(self, "help",
"Available commands")
ASSET_ZEPHYR_1_07 = Asset(
('https://github.com/AspeedTech-BMC'
'/zephyr/releases/download/v00.01.07/ast1030-evb-demo.zip'),
'ad52e27959746988afaed8429bf4e12ab988c05c4d07c9d90e13ec6f7be4574c')
def test_ast1030_zephyros_1_07(self):
self.set_machine('ast1030-evb')
zip_file = self.ASSET_ZEPHYR_1_07.fetch()
kernel_name = "ast1030-evb-demo/zephyr.bin"
with ZipFile(zip_file, 'r') as zf:
zf.extract(kernel_name, path=self.workdir)
kernel_file = os.path.join(self.workdir, kernel_name)
self.vm.set_console()
self.vm.add_args('-kernel', kernel_file, '-nographic')
self.vm.launch()
self.wait_for_console_pattern("Booting Zephyr OS")
for shell_cmd in [
'kernel stacks',
'otp info conf',
'otp info scu',
'hwinfo devid',
'crypto aes256_cbc_vault',
'random get',
'jtag JTAG1 sw_xfer high TMS',
'adc ADC0 resolution 12',
'adc ADC0 read 42',
'adc ADC1 read 69',
'i2c scan I2C_0',
'i3c attach I3C_0',
'hash test',
'kernel uptime',
'kernel reboot warm',
'kernel uptime',
'kernel reboot cold',
'kernel uptime',
]: exec_command_and_wait_for_pattern(self, shell_cmd, "uart:~$")
if __name__ == '__main__':
LinuxKernelTest.main()

View file

@ -0,0 +1,59 @@
#!/usr/bin/env python3
#
# Functional test that boots the ASPEED machines
#
# SPDX-License-Identifier: GPL-2.0-or-later
from qemu_test import Asset
from aspeed import AspeedTest
from qemu_test import exec_command_and_wait_for_pattern
from qemu_test.utils import archive_extract
class AST2500Machine(AspeedTest):
ASSET_BR2_202311_AST2500_FLASH = Asset(
('https://github.com/legoater/qemu-aspeed-boot/raw/master/'
'images/ast2500-evb/buildroot-2023.11/flash.img'),
'c23db6160cf77d0258397eb2051162c8473a56c441417c52a91ba217186e715f')
def test_arm_ast2500_evb_buildroot(self):
self.set_machine('ast2500-evb')
image_path = self.ASSET_BR2_202311_AST2500_FLASH.fetch()
self.vm.add_args('-device',
'tmp105,bus=aspeed.i2c.bus.3,address=0x4d,id=tmp-test');
self.do_test_arm_aspeed_buildroot_start(image_path, '0x0',
'ast2500-evb login:')
exec_command_and_wait_for_pattern(self,
'echo lm75 0x4d > /sys/class/i2c-dev/i2c-3/device/new_device',
'i2c i2c-3: new_device: Instantiated device lm75 at 0x4d');
exec_command_and_wait_for_pattern(self,
'cat /sys/class/hwmon/hwmon1/temp1_input', '0')
self.vm.cmd('qom-set', path='/machine/peripheral/tmp-test',
property='temperature', value=18000);
exec_command_and_wait_for_pattern(self,
'cat /sys/class/hwmon/hwmon1/temp1_input', '18000')
self.do_test_arm_aspeed_buildroot_poweroff()
ASSET_SDK_V806_AST2500 = Asset(
'https://github.com/AspeedTech-BMC/openbmc/releases/download/v08.06/ast2500-default-obmc.tar.gz',
'e1755f3cadff69190438c688d52dd0f0d399b70a1e14b1d3d5540fc4851d38ca')
def test_arm_ast2500_evb_sdk(self):
self.set_machine('ast2500-evb')
image_path = self.ASSET_SDK_V806_AST2500.fetch()
archive_extract(image_path, self.workdir)
self.do_test_arm_aspeed_sdk_start(
self.workdir + '/ast2500-default/image-bmc')
self.wait_for_console_pattern('ast2500-default login:')
if __name__ == '__main__':
AspeedTest.main()

View file

@ -0,0 +1,143 @@
#!/usr/bin/env python3
#
# Functional test that boots the ASPEED machines
#
# SPDX-License-Identifier: GPL-2.0-or-later
import os
import time
import tempfile
import subprocess
from qemu_test import Asset
from aspeed import AspeedTest
from qemu_test import exec_command_and_wait_for_pattern
from qemu_test import has_cmd
from qemu_test.utils import archive_extract
from unittest import skipUnless
class AST2600Machine(AspeedTest):
ASSET_BR2_202311_AST2600_FLASH = Asset(
('https://github.com/legoater/qemu-aspeed-boot/raw/master/'
'images/ast2600-evb/buildroot-2023.11/flash.img'),
'b62808daef48b438d0728ee07662290490ecfa65987bb91294cafb1bb7ad1a68')
def test_arm_ast2600_evb_buildroot(self):
self.set_machine('ast2600-evb')
image_path = self.ASSET_BR2_202311_AST2600_FLASH.fetch()
self.vm.add_args('-device',
'tmp105,bus=aspeed.i2c.bus.3,address=0x4d,id=tmp-test');
self.vm.add_args('-device',
'ds1338,bus=aspeed.i2c.bus.3,address=0x32');
self.vm.add_args('-device',
'i2c-echo,bus=aspeed.i2c.bus.3,address=0x42');
self.do_test_arm_aspeed_buildroot_start(image_path, '0xf00',
'ast2600-evb login:')
exec_command_and_wait_for_pattern(self,
'echo lm75 0x4d > /sys/class/i2c-dev/i2c-3/device/new_device',
'i2c i2c-3: new_device: Instantiated device lm75 at 0x4d');
exec_command_and_wait_for_pattern(self,
'cat /sys/class/hwmon/hwmon1/temp1_input', '0')
self.vm.cmd('qom-set', path='/machine/peripheral/tmp-test',
property='temperature', value=18000);
exec_command_and_wait_for_pattern(self,
'cat /sys/class/hwmon/hwmon1/temp1_input', '18000')
exec_command_and_wait_for_pattern(self,
'echo ds1307 0x32 > /sys/class/i2c-dev/i2c-3/device/new_device',
'i2c i2c-3: new_device: Instantiated device ds1307 at 0x32');
year = time.strftime("%Y")
exec_command_and_wait_for_pattern(self, 'hwclock -f /dev/rtc1', year);
exec_command_and_wait_for_pattern(self,
'echo slave-24c02 0x1064 > /sys/bus/i2c/devices/i2c-3/new_device',
'i2c i2c-3: new_device: Instantiated device slave-24c02 at 0x64');
exec_command_and_wait_for_pattern(self,
'i2cset -y 3 0x42 0x64 0x00 0xaa i', '#');
exec_command_and_wait_for_pattern(self,
'hexdump /sys/bus/i2c/devices/3-1064/slave-eeprom',
'0000000 ffaa ffff ffff ffff ffff ffff ffff ffff');
self.do_test_arm_aspeed_buildroot_poweroff()
ASSET_BR2_202302_AST2600_TPM_FLASH = Asset(
('https://github.com/legoater/qemu-aspeed-boot/raw/master/'
'images/ast2600-evb/buildroot-2023.02-tpm/flash.img'),
'a46009ae8a5403a0826d607215e731a8c68d27c14c41e55331706b8f9c7bd997')
@skipUnless(*has_cmd('swtpm'))
def test_arm_ast2600_evb_buildroot_tpm(self):
self.set_machine('ast2600-evb')
image_path = self.ASSET_BR2_202302_AST2600_TPM_FLASH.fetch()
tpmstate_dir = tempfile.TemporaryDirectory(prefix="qemu_")
socket = os.path.join(tpmstate_dir.name, 'swtpm-socket')
# We must put the TPM state dir in /tmp/, not the build dir,
# because some distros use AppArmor to lock down swtpm and
# restrict the set of locations it can access files in.
subprocess.run(['swtpm', 'socket', '-d', '--tpm2',
'--tpmstate', f'dir={tpmstate_dir.name}',
'--ctrl', f'type=unixio,path={socket}'])
self.vm.add_args('-chardev', f'socket,id=chrtpm,path={socket}')
self.vm.add_args('-tpmdev', 'emulator,id=tpm0,chardev=chrtpm')
self.vm.add_args('-device',
'tpm-tis-i2c,tpmdev=tpm0,bus=aspeed.i2c.bus.12,address=0x2e')
self.do_test_arm_aspeed_buildroot_start(image_path, '0xf00', 'Aspeed AST2600 EVB')
exec_command_and_wait_for_pattern(self,
'echo tpm_tis_i2c 0x2e > /sys/bus/i2c/devices/i2c-12/new_device',
'tpm_tis_i2c 12-002e: 2.0 TPM (device-id 0x1, rev-id 1)');
exec_command_and_wait_for_pattern(self,
'cat /sys/class/tpm/tpm0/pcr-sha256/0',
'B804724EA13F52A9072BA87FE8FDCC497DFC9DF9AA15B9088694639C431688E0');
self.do_test_arm_aspeed_buildroot_poweroff()
ASSET_SDK_V806_AST2600_A2 = Asset(
'https://github.com/AspeedTech-BMC/openbmc/releases/download/v08.06/ast2600-a2-obmc.tar.gz',
'9083506135f622d5e7351fcf7d4e1c7125cee5ba16141220c0ba88931f3681a4')
def test_arm_ast2600_evb_sdk(self):
self.set_machine('ast2600-evb')
image_path = self.ASSET_SDK_V806_AST2600_A2.fetch()
archive_extract(image_path, self.workdir)
self.vm.add_args('-device',
'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.do_test_arm_aspeed_sdk_start(
self.workdir + '/ast2600-a2/image-bmc')
self.wait_for_console_pattern('ast2600-a2 login:')
exec_command_and_wait_for_pattern(self, 'root', 'Password:')
exec_command_and_wait_for_pattern(self, '0penBmc', 'root@ast2600-a2:~#')
exec_command_and_wait_for_pattern(self,
'echo lm75 0x4d > /sys/class/i2c-dev/i2c-5/device/new_device',
'i2c i2c-5: new_device: Instantiated device lm75 at 0x4d');
exec_command_and_wait_for_pattern(self,
'cat /sys/class/hwmon/hwmon19/temp1_input', '0')
self.vm.cmd('qom-set', path='/machine/peripheral/tmp-test',
property='temperature', value=18000);
exec_command_and_wait_for_pattern(self,
'cat /sys/class/hwmon/hwmon19/temp1_input', '18000')
exec_command_and_wait_for_pattern(self,
'echo ds1307 0x32 > /sys/class/i2c-dev/i2c-5/device/new_device',
'i2c i2c-5: new_device: Instantiated device ds1307 at 0x32');
year = time.strftime("%Y")
exec_command_and_wait_for_pattern(self,
'/sbin/hwclock -f /dev/rtc1', year);
if __name__ == '__main__':
AspeedTest.main()

View file

@ -0,0 +1,24 @@
#!/usr/bin/env python3
#
# Functional test that boots the ASPEED machines
#
# SPDX-License-Identifier: GPL-2.0-or-later
from qemu_test import Asset
from aspeed import AspeedTest
class PalmettoMachine(AspeedTest):
ASSET_PALMETTO_FLASH = Asset(
('https://github.com/openbmc/openbmc/releases/download/2.9.0/'
'obmc-phosphor-image-palmetto.static.mtd'),
'3e13bbbc28e424865dc42f35ad672b10f2e82cdb11846bb28fa625b48beafd0d');
def test_arm_ast2400_palmetto_openbmc_v2_9_0(self):
image_path = self.ASSET_PALMETTO_FLASH.fetch()
self.do_test_arm_aspeed('palmetto-bmc', image_path)
if __name__ == '__main__':
AspeedTest.main()

View file

@ -0,0 +1,64 @@
#!/usr/bin/env python3
#
# Functional test that boots the ASPEED machines
#
# SPDX-License-Identifier: GPL-2.0-or-later
from qemu_test import Asset
from aspeed import AspeedTest
class RainierMachine(AspeedTest):
ASSET_RAINIER_EMMC = Asset(
('https://fileserver.linaro.org/s/B6pJTwWEkzSDi36/download/'
'mmc-p10bmc-20240617.qcow2'),
'd523fb478d2b84d5adc5658d08502bc64b1486955683814f89c6137518acd90b')
def test_arm_aspeed_emmc_boot(self):
self.set_machine('rainier-bmc')
self.require_netdev('user')
image_path = self.ASSET_RAINIER_EMMC.fetch()
self.vm.set_console()
self.vm.add_args('-drive',
'file=' + image_path + ',if=sd,id=sd2,index=2',
'-net', 'nic', '-net', 'user', '-snapshot')
self.vm.launch()
self.wait_for_console_pattern('U-Boot SPL 2019.04')
self.wait_for_console_pattern('Trying to boot from MMC1')
self.wait_for_console_pattern('U-Boot 2019.04')
self.wait_for_console_pattern('eMMC 2nd Boot')
self.wait_for_console_pattern('## Loading kernel from FIT Image')
self.wait_for_console_pattern('Starting kernel ...')
self.wait_for_console_pattern('Booting Linux on physical CPU 0xf00')
self.wait_for_console_pattern('mmcblk0: p1 p2 p3 p4 p5 p6 p7')
self.wait_for_console_pattern('IBM eBMC (OpenBMC for IBM Enterprise')
ASSET_DEBIAN_LINUX_ARMHF_DEB = Asset(
('http://snapshot.debian.org/archive/debian/20220606T211338Z/pool/main/l/linux/linux-image-5.17.0-2-armmp_5.17.6-1%2Bb1_armhf.deb'),
'8acb2b4439faedc2f3ed4bdb2847ad4f6e0491f73debaeb7f660c8abe4dcdc0e')
def test_arm_debian_kernel_boot(self):
self.set_machine('rainier-bmc')
deb_path = self.ASSET_DEBIAN_LINUX_ARMHF_DEB.fetch()
kernel_path = self.extract_from_deb(deb_path, '/boot/vmlinuz-5.17.0-2-armmp')
dtb_path = self.extract_from_deb(deb_path,
'/usr/lib/linux-image-5.17.0-2-armmp/aspeed-bmc-ibm-rainier.dtb')
self.vm.set_console()
self.vm.add_args('-kernel', kernel_path,
'-dtb', dtb_path,
'-net', 'nic')
self.vm.launch()
self.wait_for_console_pattern("Booting Linux on physical CPU 0xf00")
self.wait_for_console_pattern("SMP: Total of 2 processors activated")
self.wait_for_console_pattern("No filesystem could mount root")
if __name__ == '__main__':
AspeedTest.main()

View file

@ -0,0 +1,24 @@
#!/usr/bin/env python3
#
# Functional test that boots the ASPEED machines
#
# SPDX-License-Identifier: GPL-2.0-or-later
from qemu_test import Asset
from aspeed import AspeedTest
class RomulusMachine(AspeedTest):
ASSET_ROMULUS_FLASH = Asset(
('https://github.com/openbmc/openbmc/releases/download/2.9.0/'
'obmc-phosphor-image-romulus.static.mtd'),
'820341076803f1955bc31e647a512c79f9add4f5233d0697678bab4604c7bb25')
def test_arm_ast2500_romulus_openbmc_v2_9_0(self):
image_path = self.ASSET_ROMULUS_FLASH.fetch()
self.do_test_arm_aspeed('romulus-bmc', image_path)
if __name__ == '__main__':
AspeedTest.main()

View file

@ -0,0 +1,686 @@
/*
* QTest testcase for the M25P80 Flash (Using the Aspeed SPI
* Controller)
*
* Copyright (C) 2016 IBM Corp.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "qemu/osdep.h"
#include "qemu/bswap.h"
#include "libqtest-single.h"
#include "qemu/bitops.h"
#include "aspeed-smc-utils.h"
/*
* Use an explicit bswap for the values read/wrote to the flash region
* as they are BE and the Aspeed CPU is LE.
*/
static inline uint32_t make_be32(uint32_t data)
{
return bswap32(data);
}
static inline void spi_writel(const AspeedSMCTestData *data, uint64_t offset,
uint32_t value)
{
qtest_writel(data->s, data->spi_base + offset, value);
}
static inline uint32_t spi_readl(const AspeedSMCTestData *data, uint64_t offset)
{
return qtest_readl(data->s, data->spi_base + offset);
}
static inline void flash_writeb(const AspeedSMCTestData *data, uint64_t offset,
uint8_t value)
{
qtest_writeb(data->s, data->flash_base + offset, value);
}
static inline void flash_writel(const AspeedSMCTestData *data, uint64_t offset,
uint32_t value)
{
qtest_writel(data->s, data->flash_base + offset, value);
}
static inline uint8_t flash_readb(const AspeedSMCTestData *data,
uint64_t offset)
{
return qtest_readb(data->s, data->flash_base + offset);
}
static inline uint32_t flash_readl(const AspeedSMCTestData *data,
uint64_t offset)
{
return qtest_readl(data->s, data->flash_base + offset);
}
static void spi_conf(const AspeedSMCTestData *data, uint32_t value)
{
uint32_t conf = spi_readl(data, R_CONF);
conf |= value;
spi_writel(data, R_CONF, conf);
}
static void spi_conf_remove(const AspeedSMCTestData *data, uint32_t value)
{
uint32_t conf = spi_readl(data, R_CONF);
conf &= ~value;
spi_writel(data, R_CONF, conf);
}
static void spi_ce_ctrl(const AspeedSMCTestData *data, uint32_t value)
{
uint32_t conf = spi_readl(data, R_CE_CTRL);
conf |= value;
spi_writel(data, R_CE_CTRL, conf);
}
static void spi_ctrl_setmode(const AspeedSMCTestData *data, uint8_t mode,
uint8_t cmd)
{
uint32_t ctrl_reg = R_CTRL0 + data->cs * 4;
uint32_t ctrl = spi_readl(data, ctrl_reg);
ctrl &= ~(CTRL_USERMODE | 0xff << 16);
ctrl |= mode | (cmd << 16);
spi_writel(data, ctrl_reg, ctrl);
}
static void spi_ctrl_start_user(const AspeedSMCTestData *data)
{
uint32_t ctrl_reg = R_CTRL0 + data->cs * 4;
uint32_t ctrl = spi_readl(data, ctrl_reg);
ctrl |= CTRL_USERMODE | CTRL_CE_STOP_ACTIVE;
spi_writel(data, ctrl_reg, ctrl);
ctrl &= ~CTRL_CE_STOP_ACTIVE;
spi_writel(data, ctrl_reg, ctrl);
}
static void spi_ctrl_stop_user(const AspeedSMCTestData *data)
{
uint32_t ctrl_reg = R_CTRL0 + data->cs * 4;
uint32_t ctrl = spi_readl(data, ctrl_reg);
ctrl |= CTRL_USERMODE | CTRL_CE_STOP_ACTIVE;
spi_writel(data, ctrl_reg, ctrl);
}
static void spi_ctrl_set_io_mode(const AspeedSMCTestData *data, uint32_t value)
{
uint32_t ctrl_reg = R_CTRL0 + data->cs * 4;
uint32_t ctrl = spi_readl(data, ctrl_reg);
uint32_t mode;
mode = value & CTRL_IO_MODE_MASK;
ctrl &= ~CTRL_IO_MODE_MASK;
ctrl |= mode;
spi_writel(data, ctrl_reg, ctrl);
}
static void flash_reset(const AspeedSMCTestData *data)
{
spi_conf(data, 1 << (CONF_ENABLE_W0 + data->cs));
spi_ctrl_start_user(data);
flash_writeb(data, 0, RESET_ENABLE);
flash_writeb(data, 0, RESET_MEMORY);
flash_writeb(data, 0, WREN);
flash_writeb(data, 0, BULK_ERASE);
flash_writeb(data, 0, WRDI);
spi_ctrl_stop_user(data);
spi_conf_remove(data, 1 << (CONF_ENABLE_W0 + data->cs));
}
static void read_page(const AspeedSMCTestData *data, uint32_t addr,
uint32_t *page)
{
int i;
spi_ctrl_start_user(data);
flash_writeb(data, 0, EN_4BYTE_ADDR);
flash_writeb(data, 0, READ);
flash_writel(data, 0, make_be32(addr));
/* Continuous read are supported */
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
page[i] = make_be32(flash_readl(data, 0));
}
spi_ctrl_stop_user(data);
}
static void read_page_mem(const AspeedSMCTestData *data, uint32_t addr,
uint32_t *page)
{
int i;
/* move out USER mode to use direct reads from the AHB bus */
spi_ctrl_setmode(data, CTRL_READMODE, READ);
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
page[i] = make_be32(flash_readl(data, addr + i * 4));
}
}
static void write_page_mem(const AspeedSMCTestData *data, uint32_t addr,
uint32_t write_value)
{
spi_ctrl_setmode(data, CTRL_WRITEMODE, PP);
for (int i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
flash_writel(data, addr + i * 4, write_value);
}
}
static void assert_page_mem(const AspeedSMCTestData *data, uint32_t addr,
uint32_t expected_value)
{
uint32_t page[FLASH_PAGE_SIZE / 4];
read_page_mem(data, addr, page);
for (int i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
g_assert_cmphex(page[i], ==, expected_value);
}
}
void aspeed_smc_test_read_jedec(const void *data)
{
const AspeedSMCTestData *test_data = (const AspeedSMCTestData *)data;
uint32_t jedec = 0x0;
spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
spi_ctrl_start_user(test_data);
flash_writeb(test_data, 0, JEDEC_READ);
jedec |= flash_readb(test_data, 0) << 16;
jedec |= flash_readb(test_data, 0) << 8;
jedec |= flash_readb(test_data, 0);
spi_ctrl_stop_user(test_data);
flash_reset(test_data);
g_assert_cmphex(jedec, ==, test_data->jedec_id);
}
void aspeed_smc_test_erase_sector(const void *data)
{
const AspeedSMCTestData *test_data = (const AspeedSMCTestData *)data;
uint32_t some_page_addr = test_data->page_addr;
uint32_t page[FLASH_PAGE_SIZE / 4];
int i;
spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
/*
* Previous page should be full of 0xffs after backend is
* initialized
*/
read_page(test_data, some_page_addr - FLASH_PAGE_SIZE, page);
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
g_assert_cmphex(page[i], ==, 0xffffffff);
}
spi_ctrl_start_user(test_data);
flash_writeb(test_data, 0, EN_4BYTE_ADDR);
flash_writeb(test_data, 0, WREN);
flash_writeb(test_data, 0, PP);
flash_writel(test_data, 0, make_be32(some_page_addr));
/* Fill the page with its own addresses */
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
flash_writel(test_data, 0, make_be32(some_page_addr + i * 4));
}
spi_ctrl_stop_user(test_data);
/* Check the page is correctly written */
read_page(test_data, some_page_addr, page);
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
g_assert_cmphex(page[i], ==, some_page_addr + i * 4);
}
spi_ctrl_start_user(test_data);
flash_writeb(test_data, 0, WREN);
flash_writeb(test_data, 0, EN_4BYTE_ADDR);
flash_writeb(test_data, 0, ERASE_SECTOR);
flash_writel(test_data, 0, make_be32(some_page_addr));
spi_ctrl_stop_user(test_data);
/* Check the page is erased */
read_page(test_data, some_page_addr, page);
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
g_assert_cmphex(page[i], ==, 0xffffffff);
}
flash_reset(test_data);
}
void aspeed_smc_test_erase_all(const void *data)
{
const AspeedSMCTestData *test_data = (const AspeedSMCTestData *)data;
uint32_t some_page_addr = test_data->page_addr;
uint32_t page[FLASH_PAGE_SIZE / 4];
int i;
spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
/*
* Previous page should be full of 0xffs after backend is
* initialized
*/
read_page(test_data, some_page_addr - FLASH_PAGE_SIZE, page);
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
g_assert_cmphex(page[i], ==, 0xffffffff);
}
spi_ctrl_start_user(test_data);
flash_writeb(test_data, 0, EN_4BYTE_ADDR);
flash_writeb(test_data, 0, WREN);
flash_writeb(test_data, 0, PP);
flash_writel(test_data, 0, make_be32(some_page_addr));
/* Fill the page with its own addresses */
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
flash_writel(test_data, 0, make_be32(some_page_addr + i * 4));
}
spi_ctrl_stop_user(test_data);
/* Check the page is correctly written */
read_page(test_data, some_page_addr, page);
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
g_assert_cmphex(page[i], ==, some_page_addr + i * 4);
}
spi_ctrl_start_user(test_data);
flash_writeb(test_data, 0, WREN);
flash_writeb(test_data, 0, BULK_ERASE);
spi_ctrl_stop_user(test_data);
/* Check the page is erased */
read_page(test_data, some_page_addr, page);
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
g_assert_cmphex(page[i], ==, 0xffffffff);
}
flash_reset(test_data);
}
void aspeed_smc_test_write_page(const void *data)
{
const AspeedSMCTestData *test_data = (const AspeedSMCTestData *)data;
uint32_t my_page_addr = test_data->page_addr;
uint32_t some_page_addr = my_page_addr + FLASH_PAGE_SIZE;
uint32_t page[FLASH_PAGE_SIZE / 4];
int i;
spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
spi_ctrl_start_user(test_data);
flash_writeb(test_data, 0, EN_4BYTE_ADDR);
flash_writeb(test_data, 0, WREN);
flash_writeb(test_data, 0, PP);
flash_writel(test_data, 0, make_be32(my_page_addr));
/* Fill the page with its own addresses */
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
flash_writel(test_data, 0, make_be32(my_page_addr + i * 4));
}
spi_ctrl_stop_user(test_data);
/* Check what was written */
read_page(test_data, my_page_addr, page);
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
}
/* Check some other page. It should be full of 0xff */
read_page(test_data, some_page_addr, page);
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
g_assert_cmphex(page[i], ==, 0xffffffff);
}
flash_reset(test_data);
}
void aspeed_smc_test_read_page_mem(const void *data)
{
const AspeedSMCTestData *test_data = (const AspeedSMCTestData *)data;
uint32_t my_page_addr = test_data->page_addr;
uint32_t some_page_addr = my_page_addr + FLASH_PAGE_SIZE;
uint32_t page[FLASH_PAGE_SIZE / 4];
int i;
/*
* Enable 4BYTE mode for controller.
*/
spi_ce_ctrl(test_data, 1 << (CRTL_EXTENDED0 + test_data->cs));
/* Enable 4BYTE mode for flash. */
spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
spi_ctrl_start_user(test_data);
flash_writeb(test_data, 0, EN_4BYTE_ADDR);
flash_writeb(test_data, 0, WREN);
flash_writeb(test_data, 0, PP);
flash_writel(test_data, 0, make_be32(my_page_addr));
/* Fill the page with its own addresses */
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
flash_writel(test_data, 0, make_be32(my_page_addr + i * 4));
}
spi_ctrl_stop_user(test_data);
spi_conf_remove(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
/* Check what was written */
read_page_mem(test_data, my_page_addr, page);
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
}
/* Check some other page. It should be full of 0xff */
read_page_mem(test_data, some_page_addr, page);
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
g_assert_cmphex(page[i], ==, 0xffffffff);
}
flash_reset(test_data);
}
void aspeed_smc_test_write_page_mem(const void *data)
{
const AspeedSMCTestData *test_data = (const AspeedSMCTestData *)data;
uint32_t my_page_addr = test_data->page_addr;
uint32_t page[FLASH_PAGE_SIZE / 4];
int i;
/*
* Enable 4BYTE mode for controller.
*/
spi_ce_ctrl(test_data, 1 << (CRTL_EXTENDED0 + test_data->cs));
/* Enable 4BYTE mode for flash. */
spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
spi_ctrl_start_user(test_data);
flash_writeb(test_data, 0, EN_4BYTE_ADDR);
flash_writeb(test_data, 0, WREN);
spi_ctrl_stop_user(test_data);
/* move out USER mode to use direct writes to the AHB bus */
spi_ctrl_setmode(test_data, CTRL_WRITEMODE, PP);
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
flash_writel(test_data, my_page_addr + i * 4,
make_be32(my_page_addr + i * 4));
}
/* Check what was written */
read_page_mem(test_data, my_page_addr, page);
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
}
flash_reset(test_data);
}
void aspeed_smc_test_read_status_reg(const void *data)
{
const AspeedSMCTestData *test_data = (const AspeedSMCTestData *)data;
uint8_t r;
spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
spi_ctrl_start_user(test_data);
flash_writeb(test_data, 0, RDSR);
r = flash_readb(test_data, 0);
spi_ctrl_stop_user(test_data);
g_assert_cmphex(r & SR_WEL, ==, 0);
g_assert(!qtest_qom_get_bool
(test_data->s, test_data->node, "write-enable"));
spi_ctrl_start_user(test_data);
flash_writeb(test_data, 0, WREN);
flash_writeb(test_data, 0, RDSR);
r = flash_readb(test_data, 0);
spi_ctrl_stop_user(test_data);
g_assert_cmphex(r & SR_WEL, ==, SR_WEL);
g_assert(qtest_qom_get_bool
(test_data->s, test_data->node, "write-enable"));
spi_ctrl_start_user(test_data);
flash_writeb(test_data, 0, WRDI);
flash_writeb(test_data, 0, RDSR);
r = flash_readb(test_data, 0);
spi_ctrl_stop_user(test_data);
g_assert_cmphex(r & SR_WEL, ==, 0);
g_assert(!qtest_qom_get_bool
(test_data->s, test_data->node, "write-enable"));
flash_reset(test_data);
}
void aspeed_smc_test_status_reg_write_protection(const void *data)
{
const AspeedSMCTestData *test_data = (const AspeedSMCTestData *)data;
uint8_t r;
spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
/* default case: WP# is high and SRWD is low -> status register writable */
spi_ctrl_start_user(test_data);
flash_writeb(test_data, 0, WREN);
/* test ability to write SRWD */
flash_writeb(test_data, 0, WRSR);
flash_writeb(test_data, 0, SRWD);
flash_writeb(test_data, 0, RDSR);
r = flash_readb(test_data, 0);
spi_ctrl_stop_user(test_data);
g_assert_cmphex(r & SRWD, ==, SRWD);
/* WP# high and SRWD high -> status register writable */
spi_ctrl_start_user(test_data);
flash_writeb(test_data, 0, WREN);
/* test ability to write SRWD */
flash_writeb(test_data, 0, WRSR);
flash_writeb(test_data, 0, 0);
flash_writeb(test_data, 0, RDSR);
r = flash_readb(test_data, 0);
spi_ctrl_stop_user(test_data);
g_assert_cmphex(r & SRWD, ==, 0);
/* WP# low and SRWD low -> status register writable */
qtest_set_irq_in(test_data->s, test_data->node, "WP#", 0, 0);
spi_ctrl_start_user(test_data);
flash_writeb(test_data, 0, WREN);
/* test ability to write SRWD */
flash_writeb(test_data, 0, WRSR);
flash_writeb(test_data, 0, SRWD);
flash_writeb(test_data, 0, RDSR);
r = flash_readb(test_data, 0);
spi_ctrl_stop_user(test_data);
g_assert_cmphex(r & SRWD, ==, SRWD);
/* WP# low and SRWD high -> status register NOT writable */
spi_ctrl_start_user(test_data);
flash_writeb(test_data, 0 , WREN);
/* test ability to write SRWD */
flash_writeb(test_data, 0, WRSR);
flash_writeb(test_data, 0, 0);
flash_writeb(test_data, 0, RDSR);
r = flash_readb(test_data, 0);
spi_ctrl_stop_user(test_data);
/* write is not successful */
g_assert_cmphex(r & SRWD, ==, SRWD);
qtest_set_irq_in(test_data->s, test_data->node, "WP#", 0, 1);
flash_reset(test_data);
}
void aspeed_smc_test_write_block_protect(const void *data)
{
const AspeedSMCTestData *test_data = (const AspeedSMCTestData *)data;
uint32_t sector_size = 65536;
uint32_t n_sectors = 512;
spi_ce_ctrl(test_data, 1 << (CRTL_EXTENDED0 + test_data->cs));
spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
uint32_t bp_bits = 0b0;
for (int i = 0; i < 16; i++) {
bp_bits = ((i & 0b1000) << 3) | ((i & 0b0111) << 2);
spi_ctrl_start_user(test_data);
flash_writeb(test_data, 0, WREN);
flash_writeb(test_data, 0, BULK_ERASE);
flash_writeb(test_data, 0, WREN);
flash_writeb(test_data, 0, WRSR);
flash_writeb(test_data, 0, bp_bits);
flash_writeb(test_data, 0, EN_4BYTE_ADDR);
flash_writeb(test_data, 0, WREN);
spi_ctrl_stop_user(test_data);
uint32_t num_protected_sectors = i ? MIN(1 << (i - 1), n_sectors) : 0;
uint32_t protection_start = n_sectors - num_protected_sectors;
uint32_t protection_end = n_sectors;
for (int sector = 0; sector < n_sectors; sector++) {
uint32_t addr = sector * sector_size;
assert_page_mem(test_data, addr, 0xffffffff);
write_page_mem(test_data, addr, make_be32(0xabcdef12));
uint32_t expected_value = protection_start <= sector
&& sector < protection_end
? 0xffffffff : 0xabcdef12;
assert_page_mem(test_data, addr, expected_value);
}
}
flash_reset(test_data);
}
void aspeed_smc_test_write_block_protect_bottom_bit(const void *data)
{
const AspeedSMCTestData *test_data = (const AspeedSMCTestData *)data;
uint32_t sector_size = 65536;
uint32_t n_sectors = 512;
spi_ce_ctrl(test_data, 1 << (CRTL_EXTENDED0 + test_data->cs));
spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
/* top bottom bit is enabled */
uint32_t bp_bits = 0b00100 << 3;
for (int i = 0; i < 16; i++) {
bp_bits = (((i & 0b1000) | 0b0100) << 3) | ((i & 0b0111) << 2);
spi_ctrl_start_user(test_data);
flash_writeb(test_data, 0, WREN);
flash_writeb(test_data, 0, BULK_ERASE);
flash_writeb(test_data, 0, WREN);
flash_writeb(test_data, 0, WRSR);
flash_writeb(test_data, 0, bp_bits);
flash_writeb(test_data, 0, EN_4BYTE_ADDR);
flash_writeb(test_data, 0, WREN);
spi_ctrl_stop_user(test_data);
uint32_t num_protected_sectors = i ? MIN(1 << (i - 1), n_sectors) : 0;
uint32_t protection_start = 0;
uint32_t protection_end = num_protected_sectors;
for (int sector = 0; sector < n_sectors; sector++) {
uint32_t addr = sector * sector_size;
assert_page_mem(test_data, addr, 0xffffffff);
write_page_mem(test_data, addr, make_be32(0xabcdef12));
uint32_t expected_value = protection_start <= sector
&& sector < protection_end
? 0xffffffff : 0xabcdef12;
assert_page_mem(test_data, addr, expected_value);
}
}
flash_reset(test_data);
}
void aspeed_smc_test_write_page_qpi(const void *data)
{
const AspeedSMCTestData *test_data = (const AspeedSMCTestData *)data;
uint32_t my_page_addr = test_data->page_addr;
uint32_t some_page_addr = my_page_addr + FLASH_PAGE_SIZE;
uint32_t page[FLASH_PAGE_SIZE / 4];
uint32_t page_pattern[] = {
0xebd8c134, 0x5da196bc, 0xae15e729, 0x5085ccdf
};
int i;
spi_conf(test_data, 1 << (CONF_ENABLE_W0 + test_data->cs));
spi_ctrl_start_user(test_data);
flash_writeb(test_data, 0, EN_4BYTE_ADDR);
flash_writeb(test_data, 0, WREN);
flash_writeb(test_data, 0, PP);
flash_writel(test_data, 0, make_be32(my_page_addr));
/* Set QPI mode */
spi_ctrl_set_io_mode(test_data, CTRL_IO_QUAD_IO);
/* Fill the page pattern */
for (i = 0; i < ARRAY_SIZE(page_pattern); i++) {
flash_writel(test_data, 0, make_be32(page_pattern[i]));
}
/* Fill the page with its own addresses */
for (; i < FLASH_PAGE_SIZE / 4; i++) {
flash_writel(test_data, 0, make_be32(my_page_addr + i * 4));
}
/* Restore io mode */
spi_ctrl_set_io_mode(test_data, 0);
spi_ctrl_stop_user(test_data);
/* Check what was written */
read_page(test_data, my_page_addr, page);
for (i = 0; i < ARRAY_SIZE(page_pattern); i++) {
g_assert_cmphex(page[i], ==, page_pattern[i]);
}
for (; i < FLASH_PAGE_SIZE / 4; i++) {
g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
}
/* Check some other page. It should be full of 0xff */
read_page(test_data, some_page_addr, page);
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
g_assert_cmphex(page[i], ==, 0xffffffff);
}
flash_reset(test_data);
}

View file

@ -0,0 +1,95 @@
/*
* QTest testcase for the M25P80 Flash (Using the Aspeed SPI
* Controller)
*
* Copyright (C) 2016 IBM Corp.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef TESTS_ASPEED_SMC_UTILS_H
#define TESTS_ASPEED_SMC_UTILS_H
#include "qemu/osdep.h"
#include "qemu/bswap.h"
#include "libqtest-single.h"
#include "qemu/bitops.h"
/*
* ASPEED SPI Controller registers
*/
#define R_CONF 0x00
#define CONF_ENABLE_W0 16
#define R_CE_CTRL 0x04
#define CRTL_EXTENDED0 0 /* 32 bit addressing for SPI */
#define R_CTRL0 0x10
#define CTRL_IO_QUAD_IO BIT(31)
#define CTRL_CE_STOP_ACTIVE BIT(2)
#define CTRL_READMODE 0x0
#define CTRL_FREADMODE 0x1
#define CTRL_WRITEMODE 0x2
#define CTRL_USERMODE 0x3
#define SR_WEL BIT(1)
/*
* Flash commands
*/
enum {
JEDEC_READ = 0x9f,
RDSR = 0x5,
WRDI = 0x4,
BULK_ERASE = 0xc7,
READ = 0x03,
PP = 0x02,
WRSR = 0x1,
WREN = 0x6,
SRWD = 0x80,
RESET_ENABLE = 0x66,
RESET_MEMORY = 0x99,
EN_4BYTE_ADDR = 0xB7,
ERASE_SECTOR = 0xd8,
};
#define CTRL_IO_MODE_MASK (BIT(31) | BIT(30) | BIT(29) | BIT(28))
#define FLASH_PAGE_SIZE 256
typedef struct AspeedSMCTestData {
QTestState *s;
uint64_t spi_base;
uint64_t flash_base;
uint32_t jedec_id;
char *tmp_path;
uint8_t cs;
const char *node;
uint32_t page_addr;
} AspeedSMCTestData;
void aspeed_smc_test_read_jedec(const void *data);
void aspeed_smc_test_erase_sector(const void *data);
void aspeed_smc_test_erase_all(const void *data);
void aspeed_smc_test_write_page(const void *data);
void aspeed_smc_test_read_page_mem(const void *data);
void aspeed_smc_test_write_page_mem(const void *data);
void aspeed_smc_test_read_status_reg(const void *data);
void aspeed_smc_test_status_reg_write_protection(const void *data);
void aspeed_smc_test_write_block_protect(const void *data);
void aspeed_smc_test_write_block_protect_bottom_bit(const void *data);
void aspeed_smc_test_write_page_qpi(const void *data);
#endif /* TESTS_ASPEED_SMC_UTILS_H */

View file

@ -27,625 +27,206 @@
#include "qemu/bswap.h" #include "qemu/bswap.h"
#include "libqtest-single.h" #include "libqtest-single.h"
#include "qemu/bitops.h" #include "qemu/bitops.h"
#include "aspeed-smc-utils.h"
/* static void test_palmetto_bmc(AspeedSMCTestData *data)
* ASPEED SPI Controller registers
*/
#define R_CONF 0x00
#define CONF_ENABLE_W0 (1 << 16)
#define R_CE_CTRL 0x04
#define CRTL_EXTENDED0 0 /* 32 bit addressing for SPI */
#define R_CTRL0 0x10
#define CTRL_CE_STOP_ACTIVE (1 << 2)
#define CTRL_READMODE 0x0
#define CTRL_FREADMODE 0x1
#define CTRL_WRITEMODE 0x2
#define CTRL_USERMODE 0x3
#define SR_WEL BIT(1)
#define ASPEED_FMC_BASE 0x1E620000
#define ASPEED_FLASH_BASE 0x20000000
/*
* Flash commands
*/
enum {
JEDEC_READ = 0x9f,
RDSR = 0x5,
WRDI = 0x4,
BULK_ERASE = 0xc7,
READ = 0x03,
PP = 0x02,
WRSR = 0x1,
WREN = 0x6,
SRWD = 0x80,
RESET_ENABLE = 0x66,
RESET_MEMORY = 0x99,
EN_4BYTE_ADDR = 0xB7,
ERASE_SECTOR = 0xd8,
};
#define FLASH_JEDEC 0x20ba19 /* n25q256a */
#define FLASH_SIZE (32 * 1024 * 1024)
#define FLASH_PAGE_SIZE 256
/*
* Use an explicit bswap for the values read/wrote to the flash region
* as they are BE and the Aspeed CPU is LE.
*/
static inline uint32_t make_be32(uint32_t data)
{ {
return bswap32(data); int ret;
int fd;
fd = g_file_open_tmp("qtest.m25p80.n25q256a.XXXXXX", &data->tmp_path, NULL);
g_assert(fd >= 0);
ret = ftruncate(fd, 32 * 1024 * 1024);
g_assert(ret == 0);
close(fd);
data->s = qtest_initf("-m 256 -machine palmetto-bmc "
"-drive file=%s,format=raw,if=mtd",
data->tmp_path);
/* fmc cs0 with n25q256a flash */
data->flash_base = 0x20000000;
data->spi_base = 0x1E620000;
data->jedec_id = 0x20ba19;
data->cs = 0;
data->node = "/machine/soc/fmc/ssi.0/child[0]";
/* beyond 16MB */
data->page_addr = 0x14000 * FLASH_PAGE_SIZE;
qtest_add_data_func("/ast2400/smc/read_jedec",
data, aspeed_smc_test_read_jedec);
qtest_add_data_func("/ast2400/smc/erase_sector",
data, aspeed_smc_test_erase_sector);
qtest_add_data_func("/ast2400/smc/erase_all",
data, aspeed_smc_test_erase_all);
qtest_add_data_func("/ast2400/smc/write_page",
data, aspeed_smc_test_write_page);
qtest_add_data_func("/ast2400/smc/read_page_mem",
data, aspeed_smc_test_read_page_mem);
qtest_add_data_func("/ast2400/smc/write_page_mem",
data, aspeed_smc_test_write_page_mem);
qtest_add_data_func("/ast2400/smc/read_status_reg",
data, aspeed_smc_test_read_status_reg);
qtest_add_data_func("/ast2400/smc/status_reg_write_protection",
data, aspeed_smc_test_status_reg_write_protection);
qtest_add_data_func("/ast2400/smc/write_block_protect",
data, aspeed_smc_test_write_block_protect);
qtest_add_data_func("/ast2400/smc/write_block_protect_bottom_bit",
data, aspeed_smc_test_write_block_protect_bottom_bit);
} }
static void spi_conf(uint32_t value) static void test_ast2500_evb(AspeedSMCTestData *data)
{ {
uint32_t conf = readl(ASPEED_FMC_BASE + R_CONF); int ret;
int fd;
conf |= value; fd = g_file_open_tmp("qtest.m25p80.mx25l25635e.XXXXXX",
writel(ASPEED_FMC_BASE + R_CONF, conf); &data->tmp_path, NULL);
g_assert(fd >= 0);
ret = ftruncate(fd, 32 * 1024 * 1024);
g_assert(ret == 0);
close(fd);
data->s = qtest_initf("-machine ast2500-evb "
"-drive file=%s,format=raw,if=mtd",
data->tmp_path);
/* fmc cs0 with mx25l25635e flash */
data->flash_base = 0x20000000;
data->spi_base = 0x1E620000;
data->jedec_id = 0xc22019;
data->cs = 0;
data->node = "/machine/soc/fmc/ssi.0/child[0]";
/* beyond 16MB */
data->page_addr = 0x14000 * FLASH_PAGE_SIZE;
qtest_add_data_func("/ast2500/smc/read_jedec",
data, aspeed_smc_test_read_jedec);
qtest_add_data_func("/ast2500/smc/erase_sector",
data, aspeed_smc_test_erase_sector);
qtest_add_data_func("/ast2500/smc/erase_all",
data, aspeed_smc_test_erase_all);
qtest_add_data_func("/ast2500/smc/write_page",
data, aspeed_smc_test_write_page);
qtest_add_data_func("/ast2500/smc/read_page_mem",
data, aspeed_smc_test_read_page_mem);
qtest_add_data_func("/ast2500/smc/write_page_mem",
data, aspeed_smc_test_write_page_mem);
qtest_add_data_func("/ast2500/smc/read_status_reg",
data, aspeed_smc_test_read_status_reg);
qtest_add_data_func("/ast2500/smc/write_page_qpi",
data, aspeed_smc_test_write_page_qpi);
} }
static void spi_conf_remove(uint32_t value) static void test_ast2600_evb(AspeedSMCTestData *data)
{ {
uint32_t conf = readl(ASPEED_FMC_BASE + R_CONF); int ret;
int fd;
conf &= ~value; fd = g_file_open_tmp("qtest.m25p80.mx66u51235f.XXXXXX",
writel(ASPEED_FMC_BASE + R_CONF, conf); &data->tmp_path, NULL);
g_assert(fd >= 0);
ret = ftruncate(fd, 64 * 1024 * 1024);
g_assert(ret == 0);
close(fd);
data->s = qtest_initf("-machine ast2600-evb "
"-drive file=%s,format=raw,if=mtd",
data->tmp_path);
/* fmc cs0 with mx66u51235f flash */
data->flash_base = 0x20000000;
data->spi_base = 0x1E620000;
data->jedec_id = 0xc2253a;
data->cs = 0;
data->node = "/machine/soc/fmc/ssi.0/child[0]";
/* beyond 16MB */
data->page_addr = 0x14000 * FLASH_PAGE_SIZE;
qtest_add_data_func("/ast2600/smc/read_jedec",
data, aspeed_smc_test_read_jedec);
qtest_add_data_func("/ast2600/smc/erase_sector",
data, aspeed_smc_test_erase_sector);
qtest_add_data_func("/ast2600/smc/erase_all",
data, aspeed_smc_test_erase_all);
qtest_add_data_func("/ast2600/smc/write_page",
data, aspeed_smc_test_write_page);
qtest_add_data_func("/ast2600/smc/read_page_mem",
data, aspeed_smc_test_read_page_mem);
qtest_add_data_func("/ast2600/smc/write_page_mem",
data, aspeed_smc_test_write_page_mem);
qtest_add_data_func("/ast2600/smc/read_status_reg",
data, aspeed_smc_test_read_status_reg);
qtest_add_data_func("/ast2600/smc/write_page_qpi",
data, aspeed_smc_test_write_page_qpi);
} }
static void spi_ce_ctrl(uint32_t value) static void test_ast1030_evb(AspeedSMCTestData *data)
{ {
uint32_t conf = readl(ASPEED_FMC_BASE + R_CE_CTRL); int ret;
int fd;
conf |= value;
writel(ASPEED_FMC_BASE + R_CE_CTRL, conf); fd = g_file_open_tmp("qtest.m25p80.w25q80bl.XXXXXX",
} &data->tmp_path, NULL);
g_assert(fd >= 0);
static void spi_ctrl_setmode(uint8_t mode, uint8_t cmd) ret = ftruncate(fd, 1 * 1024 * 1024);
{ g_assert(ret == 0);
uint32_t ctrl = readl(ASPEED_FMC_BASE + R_CTRL0); close(fd);
ctrl &= ~(CTRL_USERMODE | 0xff << 16);
ctrl |= mode | (cmd << 16); data->s = qtest_initf("-machine ast1030-evb "
writel(ASPEED_FMC_BASE + R_CTRL0, ctrl); "-drive file=%s,format=raw,if=mtd",
} data->tmp_path);
static void spi_ctrl_start_user(void) /* fmc cs0 with w25q80bl flash */
{ data->flash_base = 0x80000000;
uint32_t ctrl = readl(ASPEED_FMC_BASE + R_CTRL0); data->spi_base = 0x7E620000;
data->jedec_id = 0xef4014;
ctrl |= CTRL_USERMODE | CTRL_CE_STOP_ACTIVE; data->cs = 0;
writel(ASPEED_FMC_BASE + R_CTRL0, ctrl); data->node = "/machine/soc/fmc/ssi.0/child[0]";
/* beyond 512KB */
ctrl &= ~CTRL_CE_STOP_ACTIVE; data->page_addr = 0x800 * FLASH_PAGE_SIZE;
writel(ASPEED_FMC_BASE + R_CTRL0, ctrl);
} qtest_add_data_func("/ast1030/smc/read_jedec",
data, aspeed_smc_test_read_jedec);
static void spi_ctrl_stop_user(void) qtest_add_data_func("/ast1030/smc/erase_sector",
{ data, aspeed_smc_test_erase_sector);
uint32_t ctrl = readl(ASPEED_FMC_BASE + R_CTRL0); qtest_add_data_func("/ast1030/smc/erase_all",
data, aspeed_smc_test_erase_all);
ctrl |= CTRL_USERMODE | CTRL_CE_STOP_ACTIVE; qtest_add_data_func("/ast1030/smc/write_page",
writel(ASPEED_FMC_BASE + R_CTRL0, ctrl); data, aspeed_smc_test_write_page);
} qtest_add_data_func("/ast1030/smc/read_page_mem",
data, aspeed_smc_test_read_page_mem);
static void flash_reset(void) qtest_add_data_func("/ast1030/smc/write_page_mem",
{ data, aspeed_smc_test_write_page_mem);
spi_conf(CONF_ENABLE_W0); qtest_add_data_func("/ast1030/smc/read_status_reg",
data, aspeed_smc_test_read_status_reg);
spi_ctrl_start_user(); qtest_add_data_func("/ast1030/smc/write_page_qpi",
writeb(ASPEED_FLASH_BASE, RESET_ENABLE); data, aspeed_smc_test_write_page_qpi);
writeb(ASPEED_FLASH_BASE, RESET_MEMORY);
writeb(ASPEED_FLASH_BASE, WREN);
writeb(ASPEED_FLASH_BASE, BULK_ERASE);
writeb(ASPEED_FLASH_BASE, WRDI);
spi_ctrl_stop_user();
spi_conf_remove(CONF_ENABLE_W0);
}
static void test_read_jedec(void)
{
uint32_t jedec = 0x0;
spi_conf(CONF_ENABLE_W0);
spi_ctrl_start_user();
writeb(ASPEED_FLASH_BASE, JEDEC_READ);
jedec |= readb(ASPEED_FLASH_BASE) << 16;
jedec |= readb(ASPEED_FLASH_BASE) << 8;
jedec |= readb(ASPEED_FLASH_BASE);
spi_ctrl_stop_user();
flash_reset();
g_assert_cmphex(jedec, ==, FLASH_JEDEC);
}
static void read_page(uint32_t addr, uint32_t *page)
{
int i;
spi_ctrl_start_user();
writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
writeb(ASPEED_FLASH_BASE, READ);
writel(ASPEED_FLASH_BASE, make_be32(addr));
/* Continuous read are supported */
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
page[i] = make_be32(readl(ASPEED_FLASH_BASE));
}
spi_ctrl_stop_user();
}
static void read_page_mem(uint32_t addr, uint32_t *page)
{
int i;
/* move out USER mode to use direct reads from the AHB bus */
spi_ctrl_setmode(CTRL_READMODE, READ);
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
page[i] = make_be32(readl(ASPEED_FLASH_BASE + addr + i * 4));
}
}
static void write_page_mem(uint32_t addr, uint32_t write_value)
{
spi_ctrl_setmode(CTRL_WRITEMODE, PP);
for (int i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
writel(ASPEED_FLASH_BASE + addr + i * 4, write_value);
}
}
static void assert_page_mem(uint32_t addr, uint32_t expected_value)
{
uint32_t page[FLASH_PAGE_SIZE / 4];
read_page_mem(addr, page);
for (int i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
g_assert_cmphex(page[i], ==, expected_value);
}
}
static void test_erase_sector(void)
{
uint32_t some_page_addr = 0x600 * FLASH_PAGE_SIZE;
uint32_t page[FLASH_PAGE_SIZE / 4];
int i;
spi_conf(CONF_ENABLE_W0);
/*
* Previous page should be full of 0xffs after backend is
* initialized
*/
read_page(some_page_addr - FLASH_PAGE_SIZE, page);
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
g_assert_cmphex(page[i], ==, 0xffffffff);
}
spi_ctrl_start_user();
writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
writeb(ASPEED_FLASH_BASE, WREN);
writeb(ASPEED_FLASH_BASE, PP);
writel(ASPEED_FLASH_BASE, make_be32(some_page_addr));
/* Fill the page with its own addresses */
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
writel(ASPEED_FLASH_BASE, make_be32(some_page_addr + i * 4));
}
spi_ctrl_stop_user();
/* Check the page is correctly written */
read_page(some_page_addr, page);
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
g_assert_cmphex(page[i], ==, some_page_addr + i * 4);
}
spi_ctrl_start_user();
writeb(ASPEED_FLASH_BASE, WREN);
writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
writeb(ASPEED_FLASH_BASE, ERASE_SECTOR);
writel(ASPEED_FLASH_BASE, make_be32(some_page_addr));
spi_ctrl_stop_user();
/* Check the page is erased */
read_page(some_page_addr, page);
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
g_assert_cmphex(page[i], ==, 0xffffffff);
}
flash_reset();
}
static void test_erase_all(void)
{
uint32_t some_page_addr = 0x15000 * FLASH_PAGE_SIZE;
uint32_t page[FLASH_PAGE_SIZE / 4];
int i;
spi_conf(CONF_ENABLE_W0);
/*
* Previous page should be full of 0xffs after backend is
* initialized
*/
read_page(some_page_addr - FLASH_PAGE_SIZE, page);
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
g_assert_cmphex(page[i], ==, 0xffffffff);
}
spi_ctrl_start_user();
writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
writeb(ASPEED_FLASH_BASE, WREN);
writeb(ASPEED_FLASH_BASE, PP);
writel(ASPEED_FLASH_BASE, make_be32(some_page_addr));
/* Fill the page with its own addresses */
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
writel(ASPEED_FLASH_BASE, make_be32(some_page_addr + i * 4));
}
spi_ctrl_stop_user();
/* Check the page is correctly written */
read_page(some_page_addr, page);
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
g_assert_cmphex(page[i], ==, some_page_addr + i * 4);
}
spi_ctrl_start_user();
writeb(ASPEED_FLASH_BASE, WREN);
writeb(ASPEED_FLASH_BASE, BULK_ERASE);
spi_ctrl_stop_user();
/* Check the page is erased */
read_page(some_page_addr, page);
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
g_assert_cmphex(page[i], ==, 0xffffffff);
}
flash_reset();
}
static void test_write_page(void)
{
uint32_t my_page_addr = 0x14000 * FLASH_PAGE_SIZE; /* beyond 16MB */
uint32_t some_page_addr = 0x15000 * FLASH_PAGE_SIZE;
uint32_t page[FLASH_PAGE_SIZE / 4];
int i;
spi_conf(CONF_ENABLE_W0);
spi_ctrl_start_user();
writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
writeb(ASPEED_FLASH_BASE, WREN);
writeb(ASPEED_FLASH_BASE, PP);
writel(ASPEED_FLASH_BASE, make_be32(my_page_addr));
/* Fill the page with its own addresses */
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
writel(ASPEED_FLASH_BASE, make_be32(my_page_addr + i * 4));
}
spi_ctrl_stop_user();
/* Check what was written */
read_page(my_page_addr, page);
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
}
/* Check some other page. It should be full of 0xff */
read_page(some_page_addr, page);
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
g_assert_cmphex(page[i], ==, 0xffffffff);
}
flash_reset();
}
static void test_read_page_mem(void)
{
uint32_t my_page_addr = 0x14000 * FLASH_PAGE_SIZE; /* beyond 16MB */
uint32_t some_page_addr = 0x15000 * FLASH_PAGE_SIZE;
uint32_t page[FLASH_PAGE_SIZE / 4];
int i;
/*
* Enable 4BYTE mode for controller. This is should be strapped by
* HW for CE0 anyhow.
*/
spi_ce_ctrl(1 << CRTL_EXTENDED0);
/* Enable 4BYTE mode for flash. */
spi_conf(CONF_ENABLE_W0);
spi_ctrl_start_user();
writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
writeb(ASPEED_FLASH_BASE, WREN);
writeb(ASPEED_FLASH_BASE, PP);
writel(ASPEED_FLASH_BASE, make_be32(my_page_addr));
/* Fill the page with its own addresses */
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
writel(ASPEED_FLASH_BASE, make_be32(my_page_addr + i * 4));
}
spi_ctrl_stop_user();
spi_conf_remove(CONF_ENABLE_W0);
/* Check what was written */
read_page_mem(my_page_addr, page);
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
}
/* Check some other page. It should be full of 0xff */
read_page_mem(some_page_addr, page);
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
g_assert_cmphex(page[i], ==, 0xffffffff);
}
flash_reset();
}
static void test_write_page_mem(void)
{
uint32_t my_page_addr = 0x15000 * FLASH_PAGE_SIZE;
uint32_t page[FLASH_PAGE_SIZE / 4];
int i;
/*
* Enable 4BYTE mode for controller. This is should be strapped by
* HW for CE0 anyhow.
*/
spi_ce_ctrl(1 << CRTL_EXTENDED0);
/* Enable 4BYTE mode for flash. */
spi_conf(CONF_ENABLE_W0);
spi_ctrl_start_user();
writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
writeb(ASPEED_FLASH_BASE, WREN);
spi_ctrl_stop_user();
/* move out USER mode to use direct writes to the AHB bus */
spi_ctrl_setmode(CTRL_WRITEMODE, PP);
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
writel(ASPEED_FLASH_BASE + my_page_addr + i * 4,
make_be32(my_page_addr + i * 4));
}
/* Check what was written */
read_page_mem(my_page_addr, page);
for (i = 0; i < FLASH_PAGE_SIZE / 4; i++) {
g_assert_cmphex(page[i], ==, my_page_addr + i * 4);
}
flash_reset();
}
static void test_read_status_reg(void)
{
uint8_t r;
spi_conf(CONF_ENABLE_W0);
spi_ctrl_start_user();
writeb(ASPEED_FLASH_BASE, RDSR);
r = readb(ASPEED_FLASH_BASE);
spi_ctrl_stop_user();
g_assert_cmphex(r & SR_WEL, ==, 0);
g_assert(!qtest_qom_get_bool
(global_qtest, "/machine/soc/fmc/ssi.0/child[0]", "write-enable"));
spi_ctrl_start_user();
writeb(ASPEED_FLASH_BASE, WREN);
writeb(ASPEED_FLASH_BASE, RDSR);
r = readb(ASPEED_FLASH_BASE);
spi_ctrl_stop_user();
g_assert_cmphex(r & SR_WEL, ==, SR_WEL);
g_assert(qtest_qom_get_bool
(global_qtest, "/machine/soc/fmc/ssi.0/child[0]", "write-enable"));
spi_ctrl_start_user();
writeb(ASPEED_FLASH_BASE, WRDI);
writeb(ASPEED_FLASH_BASE, RDSR);
r = readb(ASPEED_FLASH_BASE);
spi_ctrl_stop_user();
g_assert_cmphex(r & SR_WEL, ==, 0);
g_assert(!qtest_qom_get_bool
(global_qtest, "/machine/soc/fmc/ssi.0/child[0]", "write-enable"));
flash_reset();
}
static void test_status_reg_write_protection(void)
{
uint8_t r;
spi_conf(CONF_ENABLE_W0);
/* default case: WP# is high and SRWD is low -> status register writable */
spi_ctrl_start_user();
writeb(ASPEED_FLASH_BASE, WREN);
/* test ability to write SRWD */
writeb(ASPEED_FLASH_BASE, WRSR);
writeb(ASPEED_FLASH_BASE, SRWD);
writeb(ASPEED_FLASH_BASE, RDSR);
r = readb(ASPEED_FLASH_BASE);
spi_ctrl_stop_user();
g_assert_cmphex(r & SRWD, ==, SRWD);
/* WP# high and SRWD high -> status register writable */
spi_ctrl_start_user();
writeb(ASPEED_FLASH_BASE, WREN);
/* test ability to write SRWD */
writeb(ASPEED_FLASH_BASE, WRSR);
writeb(ASPEED_FLASH_BASE, 0);
writeb(ASPEED_FLASH_BASE, RDSR);
r = readb(ASPEED_FLASH_BASE);
spi_ctrl_stop_user();
g_assert_cmphex(r & SRWD, ==, 0);
/* WP# low and SRWD low -> status register writable */
qtest_set_irq_in(global_qtest,
"/machine/soc/fmc/ssi.0/child[0]", "WP#", 0, 0);
spi_ctrl_start_user();
writeb(ASPEED_FLASH_BASE, WREN);
/* test ability to write SRWD */
writeb(ASPEED_FLASH_BASE, WRSR);
writeb(ASPEED_FLASH_BASE, SRWD);
writeb(ASPEED_FLASH_BASE, RDSR);
r = readb(ASPEED_FLASH_BASE);
spi_ctrl_stop_user();
g_assert_cmphex(r & SRWD, ==, SRWD);
/* WP# low and SRWD high -> status register NOT writable */
spi_ctrl_start_user();
writeb(ASPEED_FLASH_BASE, WREN);
/* test ability to write SRWD */
writeb(ASPEED_FLASH_BASE, WRSR);
writeb(ASPEED_FLASH_BASE, 0);
writeb(ASPEED_FLASH_BASE, RDSR);
r = readb(ASPEED_FLASH_BASE);
spi_ctrl_stop_user();
/* write is not successful */
g_assert_cmphex(r & SRWD, ==, SRWD);
qtest_set_irq_in(global_qtest,
"/machine/soc/fmc/ssi.0/child[0]", "WP#", 0, 1);
flash_reset();
}
static void test_write_block_protect(void)
{
uint32_t sector_size = 65536;
uint32_t n_sectors = 512;
spi_ce_ctrl(1 << CRTL_EXTENDED0);
spi_conf(CONF_ENABLE_W0);
uint32_t bp_bits = 0b0;
for (int i = 0; i < 16; i++) {
bp_bits = ((i & 0b1000) << 3) | ((i & 0b0111) << 2);
spi_ctrl_start_user();
writeb(ASPEED_FLASH_BASE, WREN);
writeb(ASPEED_FLASH_BASE, BULK_ERASE);
writeb(ASPEED_FLASH_BASE, WREN);
writeb(ASPEED_FLASH_BASE, WRSR);
writeb(ASPEED_FLASH_BASE, bp_bits);
writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
writeb(ASPEED_FLASH_BASE, WREN);
spi_ctrl_stop_user();
uint32_t num_protected_sectors = i ? MIN(1 << (i - 1), n_sectors) : 0;
uint32_t protection_start = n_sectors - num_protected_sectors;
uint32_t protection_end = n_sectors;
for (int sector = 0; sector < n_sectors; sector++) {
uint32_t addr = sector * sector_size;
assert_page_mem(addr, 0xffffffff);
write_page_mem(addr, make_be32(0xabcdef12));
uint32_t expected_value = protection_start <= sector
&& sector < protection_end
? 0xffffffff : 0xabcdef12;
assert_page_mem(addr, expected_value);
}
}
flash_reset();
}
static void test_write_block_protect_bottom_bit(void)
{
uint32_t sector_size = 65536;
uint32_t n_sectors = 512;
spi_ce_ctrl(1 << CRTL_EXTENDED0);
spi_conf(CONF_ENABLE_W0);
/* top bottom bit is enabled */
uint32_t bp_bits = 0b00100 << 3;
for (int i = 0; i < 16; i++) {
bp_bits = (((i & 0b1000) | 0b0100) << 3) | ((i & 0b0111) << 2);
spi_ctrl_start_user();
writeb(ASPEED_FLASH_BASE, WREN);
writeb(ASPEED_FLASH_BASE, BULK_ERASE);
writeb(ASPEED_FLASH_BASE, WREN);
writeb(ASPEED_FLASH_BASE, WRSR);
writeb(ASPEED_FLASH_BASE, bp_bits);
writeb(ASPEED_FLASH_BASE, EN_4BYTE_ADDR);
writeb(ASPEED_FLASH_BASE, WREN);
spi_ctrl_stop_user();
uint32_t num_protected_sectors = i ? MIN(1 << (i - 1), n_sectors) : 0;
uint32_t protection_start = 0;
uint32_t protection_end = num_protected_sectors;
for (int sector = 0; sector < n_sectors; sector++) {
uint32_t addr = sector * sector_size;
assert_page_mem(addr, 0xffffffff);
write_page_mem(addr, make_be32(0xabcdef12));
uint32_t expected_value = protection_start <= sector
&& sector < protection_end
? 0xffffffff : 0xabcdef12;
assert_page_mem(addr, expected_value);
}
}
flash_reset();
} }
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
g_autofree char *tmp_path = NULL; AspeedSMCTestData palmetto_data;
AspeedSMCTestData ast2500_evb_data;
AspeedSMCTestData ast2600_evb_data;
AspeedSMCTestData ast1030_evb_data;
int ret; int ret;
int fd;
g_test_init(&argc, &argv, NULL); g_test_init(&argc, &argv, NULL);
fd = g_file_open_tmp("qtest.m25p80.XXXXXX", &tmp_path, NULL); test_palmetto_bmc(&palmetto_data);
g_assert(fd >= 0); test_ast2500_evb(&ast2500_evb_data);
ret = ftruncate(fd, FLASH_SIZE); test_ast2600_evb(&ast2600_evb_data);
g_assert(ret == 0); test_ast1030_evb(&ast1030_evb_data);
close(fd);
global_qtest = qtest_initf("-m 256 -machine palmetto-bmc "
"-drive file=%s,format=raw,if=mtd",
tmp_path);
qtest_add_func("/ast2400/smc/read_jedec", test_read_jedec);
qtest_add_func("/ast2400/smc/erase_sector", test_erase_sector);
qtest_add_func("/ast2400/smc/erase_all", test_erase_all);
qtest_add_func("/ast2400/smc/write_page", test_write_page);
qtest_add_func("/ast2400/smc/read_page_mem", test_read_page_mem);
qtest_add_func("/ast2400/smc/write_page_mem", test_write_page_mem);
qtest_add_func("/ast2400/smc/read_status_reg", test_read_status_reg);
qtest_add_func("/ast2400/smc/status_reg_write_protection",
test_status_reg_write_protection);
qtest_add_func("/ast2400/smc/write_block_protect",
test_write_block_protect);
qtest_add_func("/ast2400/smc/write_block_protect_bottom_bit",
test_write_block_protect_bottom_bit);
flash_reset();
ret = g_test_run(); ret = g_test_run();
qtest_quit(global_qtest); qtest_quit(palmetto_data.s);
unlink(tmp_path); qtest_quit(ast2500_evb_data.s);
qtest_quit(ast2600_evb_data.s);
qtest_quit(ast1030_evb_data.s);
unlink(palmetto_data.tmp_path);
unlink(ast2500_evb_data.tmp_path);
unlink(ast2600_evb_data.tmp_path);
unlink(ast1030_evb_data.tmp_path);
return ret; return ret;
} }

View file

@ -0,0 +1,71 @@
/*
* QTest testcase for the M25P80 Flash using the ASPEED SPI Controller since
* AST2700.
*
* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright (C) 2024 ASPEED Technology Inc.
*/
#include "qemu/osdep.h"
#include "qemu/bswap.h"
#include "libqtest-single.h"
#include "qemu/bitops.h"
#include "aspeed-smc-utils.h"
static void test_ast2700_evb(AspeedSMCTestData *data)
{
int ret;
int fd;
fd = g_file_open_tmp("qtest.m25p80.w25q01jvq.XXXXXX",
&data->tmp_path, NULL);
g_assert(fd >= 0);
ret = ftruncate(fd, 128 * 1024 * 1024);
g_assert(ret == 0);
close(fd);
data->s = qtest_initf("-machine ast2700-evb "
"-drive file=%s,format=raw,if=mtd",
data->tmp_path);
/* fmc cs0 with w25q01jvq flash */
data->flash_base = 0x100000000;
data->spi_base = 0x14000000;
data->jedec_id = 0xef4021;
data->cs = 0;
data->node = "/machine/soc/fmc/ssi.0/child[0]";
/* beyond 64MB */
data->page_addr = 0x40000 * FLASH_PAGE_SIZE;
qtest_add_data_func("/ast2700/smc/read_jedec",
data, aspeed_smc_test_read_jedec);
qtest_add_data_func("/ast2700/smc/erase_sector",
data, aspeed_smc_test_erase_sector);
qtest_add_data_func("/ast2700/smc/erase_all",
data, aspeed_smc_test_erase_all);
qtest_add_data_func("/ast2700/smc/write_page",
data, aspeed_smc_test_write_page);
qtest_add_data_func("/ast2700/smc/read_page_mem",
data, aspeed_smc_test_read_page_mem);
qtest_add_data_func("/ast2700/smc/write_page_mem",
data, aspeed_smc_test_write_page_mem);
qtest_add_data_func("/ast2700/smc/read_status_reg",
data, aspeed_smc_test_read_status_reg);
qtest_add_data_func("/ast2700/smc/write_page_qpi",
data, aspeed_smc_test_write_page_qpi);
}
int main(int argc, char **argv)
{
AspeedSMCTestData ast2700_evb_data;
int ret;
g_test_init(&argc, &argv, NULL);
test_ast2700_evb(&ast2700_evb_data);
ret = g_test_run();
qtest_quit(ast2700_evb_data.s);
unlink(ast2700_evb_data.tmp_path);
return ret;
}

View file

@ -214,7 +214,8 @@ qtests_aspeed = \
'aspeed_smc-test', 'aspeed_smc-test',
'aspeed_gpio-test'] 'aspeed_gpio-test']
qtests_aspeed64 = \ qtests_aspeed64 = \
['ast2700-gpio-test'] ['ast2700-gpio-test',
'ast2700-smc-test']
qtests_stm32l4x5 = \ qtests_stm32l4x5 = \
['stm32l4x5_exti-test', ['stm32l4x5_exti-test',
@ -360,6 +361,8 @@ qtests = {
'virtio-net-failover': files('migration-helpers.c'), 'virtio-net-failover': files('migration-helpers.c'),
'vmgenid-test': files('boot-sector.c', 'acpi-utils.c'), 'vmgenid-test': files('boot-sector.c', 'acpi-utils.c'),
'netdev-socket': files('netdev-socket.c', '../unit/socket-helpers.c'), 'netdev-socket': files('netdev-socket.c', '../unit/socket-helpers.c'),
'aspeed_smc-test': files('aspeed-smc-utils.c', 'aspeed_smc-test.c'),
'ast2700-smc-test': files('aspeed-smc-utils.c', 'ast2700-smc-test.c'),
} }
if vnc.found() if vnc.found()