Merge tag 'pull-aspeed-20241024' of https://github.com/legoater/qemu into staging
aspeed queue:
* Fixed GPIO interrupt status when in index mode
* Added GPIO support for the AST2700 SoC and specific test cases
* Fixed crypto controller (HACE) Accumulative hash function
* Converted Aspeed machine avocado tests to the new functional
framework. SDK tests still to be addressed.
* Fixed issue in the SSI controller when doing writes in user mode
* Added support for the WRSR2 register of Winbond flash devices
* Added SFDP table for the Windbond w25q80bl flash device
* Changed flash device models for the ast1030-a1 EVB
# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEEoPZlSPBIlev+awtgUaNDx8/77KEFAmcZ6MIACgkQUaNDx8/7
# 7KFQPA//RTxi1PmCDlzd1ffzMWEadD3CpGLJ4RgEeZpNtkx6IF2uFFBdlNgjTSmD
# B8FdIOVb8qo2omXahKIVIgoKbGgn3U3jciH67D/x4Jyp8IhW6n5XwZzKNJ7kLVHX
# IluGmlvqNumSKl3vxsLvprC0ojRiO/SfWkzS6VOwoFPM7uNDTybQicWBBoy3Jh3e
# VVlMwIeKHMQVJGpI8PQbtnFZO4HaMqWwlo0EoIJji59fdyWULLvrXzH9YhzwFVjQ
# oCNvJUBLfxLse7c13cm/LuNmw+IQtLC5OztsOOtv1XZ1MruhJ7t316eGsQEpeWcD
# Yy5RK4mIBJMExu9oxcKOqgSznQSgenvNGWg6Z9FyyKGciylafnE8GeT35WObumyD
# v9gzgeLcw5DgvDgQXaYi4IkKyezaHoE3HPbFdBEZHBt8tn5pPGmXM0lEWL5xQ5B8
# h6HphjxIlFxeHIxYenLJowLBMOt8aFXzGboF2XCLrx19OC2zvoo7klCbFeAfZpvQ
# JMXP+GsQIe7fnBMbyXGrJh9q+/7tKR4ivtTV/vnSF0FPtyzxdoSrYsUA4SZqSWvI
# ONz62p+zlE/oXBUIaFnC2Ea41YwJ7mDbmcSU1dFxmE0xRVmoYlUocoeS2VOUmTH0
# CMgEcmMXQG0vx8nipQbScbuWRCBlf0YwJ7Y7stgI8HabmsMMbIg=
# =DqCH
# -----END PGP SIGNATURE-----
# gpg: Signature made Thu 24 Oct 2024 07:27:14 BST
# 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-20241024' of https://github.com/legoater/qemu:
test/qtest/aspeed_smc-test: Fix coding style
hw/arm/aspeed: Correct fmc_model w25q80bl for ast1030-a1 EVB
hw/arm/aspeed: Correct spi_model w25q256 for ast1030-a1 EVB.
hw/block/m25p80: Add SFDP table for w25q80bl flash
hw/block:m25p80: Support write status register 2 command (0x31) for w25q01jvq
hw/block:m25p80: Fix coding style
aspeed/smc: Fix write incorrect data into flash in user mode
tests/functional: Convert most Aspeed machine tests
hw/misc/aspeed_hace: Fix SG Accumulative hashing
tests/qtest:ast2700-gpio-test: Add GPIO test case for AST2700
aspeed/soc: Support GPIO for AST2700
aspeed/soc: Correct GPIO irq 130 for AST2700
hw/gpio/aspeed: Add AST2700 support
hw/gpio/aspeed: Fix clear incorrect interrupt status for GPIO index mode
hw/gpio/aspeed: Support different memory region ops
hw/gpio/aspeed: Support to set the different memory size
hw/gpio/aspeed: Fix coding style
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
diff --git a/MAINTAINERS b/MAINTAINERS
index c3bfa13..bcaf36e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1123,6 +1123,7 @@
F: include/hw/net/ftgmac100.h
F: docs/system/arm/aspeed.rst
F: tests/*/*aspeed*
+F: tests/*/*ast2700*
F: hw/arm/fby35.c
NRF51
diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
index cf0c6c5..b4b1ce9 100644
--- a/hw/arm/aspeed.c
+++ b/hw/arm/aspeed.c
@@ -1642,8 +1642,8 @@
mc->init = aspeed_minibmc_machine_init;
amc->i2c_init = ast1030_evb_i2c_init;
mc->default_ram_size = 0;
- amc->fmc_model = "sst25vf032b";
- amc->spi_model = "sst25vf032b";
+ amc->fmc_model = "w25q80bl";
+ amc->spi_model = "w25q256";
amc->num_cs = 2;
amc->macs_mask = 0;
aspeed_machine_class_init_cpus_defaults(mc);
diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c
index 761ee11..dca660e 100644
--- a/hw/arm/aspeed_ast27x0.c
+++ b/hw/arm/aspeed_ast27x0.c
@@ -62,6 +62,7 @@
[ASPEED_GIC_REDIST] = 0x12280000,
[ASPEED_DEV_ADC] = 0x14C00000,
[ASPEED_DEV_I2C] = 0x14C0F000,
+ [ASPEED_DEV_GPIO] = 0x14C0B000,
};
#define AST2700_MAX_IRQ 288
@@ -87,8 +88,7 @@
[ASPEED_DEV_ADC] = 130,
[ASPEED_DEV_XDMA] = 5,
[ASPEED_DEV_EMMC] = 15,
- [ASPEED_DEV_GPIO] = 11,
- [ASPEED_DEV_GPIO_1_8V] = 130,
+ [ASPEED_DEV_GPIO] = 130,
[ASPEED_DEV_RTC] = 13,
[ASPEED_DEV_TIMER1] = 16,
[ASPEED_DEV_TIMER2] = 17,
@@ -124,7 +124,7 @@
static const int aspeed_soc_ast2700_gic130_intcmap[] = {
[ASPEED_DEV_I2C] = 0,
[ASPEED_DEV_ADC] = 16,
- [ASPEED_DEV_GPIO_1_8V] = 18,
+ [ASPEED_DEV_GPIO] = 18,
};
/* GICINT 131 */
@@ -373,6 +373,9 @@
snprintf(typename, sizeof(typename), "aspeed.i2c-%s", socname);
object_initialize_child(obj, "i2c", &s->i2c, typename);
+
+ snprintf(typename, sizeof(typename), "aspeed.gpio-%s", socname);
+ object_initialize_child(obj, "gpio", &s->gpio, typename);
}
/*
@@ -658,6 +661,15 @@
sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c.busses[i]), 0, irq);
}
+ /* GPIO */
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), errp)) {
+ return;
+ }
+ aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->gpio), 0,
+ sc->memmap[ASPEED_DEV_GPIO]);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio), 0,
+ aspeed_soc_get_irq(s, ASPEED_DEV_GPIO));
+
create_unimplemented_device("ast2700.dpmcu", 0x11000000, 0x40000);
create_unimplemented_device("ast2700.iomem0", 0x12000000, 0x01000000);
create_unimplemented_device("ast2700.iomem1", 0x14000000, 0x01000000);
diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c
index f7123f9..e2e84f8 100644
--- a/hw/block/m25p80.c
+++ b/hw/block/m25p80.c
@@ -61,7 +61,8 @@
*/
uint8_t id[SPI_NOR_MAX_ID_LEN];
uint8_t id_len;
- /* there is confusion between manufacturers as to what a sector is. In this
+ /*
+ * there is confusion between manufacturers as to what a sector is. In this
* device model, a "sector" is the size that is erased by the ERASE_SECTOR
* command (opcode 0xd8).
*/
@@ -168,7 +169,7 @@
/*
* Spansion read mode command length in bytes,
* the mode is currently not supported.
-*/
+ */
#define SPANSION_CONTINUOUS_READ_MODE_CMD_LEN 1
#define WINBOND_CONTINUOUS_READ_MODE_CMD_LEN 1
@@ -189,7 +190,8 @@
{ INFO("at45db081d", 0x1f2500, 0, 64 << 10, 16, ER_4K) },
- /* Atmel EEPROMS - it is assumed, that don't care bit in command
+ /*
+ * Atmel EEPROMS - it is assumed, that don't care bit in command
* is set to 0. Block protection is not supported.
*/
{ INFO("at25128a-nonjedec", 0x0, 0, 1, 131072, EEPROM) },
@@ -275,10 +277,13 @@
{ INFO_STACKED("n25q00a", 0x20bb21, 0x1000, 64 << 10, 2048, ER_4K, 4) },
{ INFO_STACKED("mt25ql01g", 0x20ba21, 0x1040, 64 << 10, 2048, ER_4K, 2) },
{ INFO_STACKED("mt25qu01g", 0x20bb21, 0x1040, 64 << 10, 2048, ER_4K, 2) },
- { INFO_STACKED("mt25ql02g", 0x20ba22, 0x1040, 64 << 10, 4096, ER_4K | ER_32K, 2) },
- { INFO_STACKED("mt25qu02g", 0x20bb22, 0x1040, 64 << 10, 4096, ER_4K | ER_32K, 2) },
+ { INFO_STACKED("mt25ql02g", 0x20ba22, 0x1040, 64 << 10, 4096,
+ ER_4K | ER_32K, 2) },
+ { INFO_STACKED("mt25qu02g", 0x20bb22, 0x1040, 64 << 10, 4096,
+ ER_4K | ER_32K, 2) },
- /* Spansion -- single (large) sector size only, at least
+ /*
+ * Spansion -- single (large) sector size only, at least
* for the chips listed here (without boot sectors).
*/
{ INFO("s25sl032p", 0x010215, 0x4d00, 64 << 10, 64, ER_4K) },
@@ -351,7 +356,8 @@
{ INFO("w25x64", 0xef3017, 0, 64 << 10, 128, ER_4K) },
{ INFO("w25q64", 0xef4017, 0, 64 << 10, 128, ER_4K) },
{ INFO("w25q80", 0xef5014, 0, 64 << 10, 16, ER_4K) },
- { INFO("w25q80bl", 0xef4014, 0, 64 << 10, 16, ER_4K) },
+ { INFO("w25q80bl", 0xef4014, 0, 64 << 10, 16, ER_4K),
+ .sfdp_read = m25p80_sfdp_w25q80bl },
{ INFO("w25q256", 0xef4019, 0, 64 << 10, 512, ER_4K),
.sfdp_read = m25p80_sfdp_w25q256 },
{ INFO("w25q512jv", 0xef4020, 0, 64 << 10, 1024, ER_4K),
@@ -425,6 +431,11 @@
RDCR_EQIO = 0x35,
RSTQIO = 0xf5,
+ /*
+ * Winbond: 0x31 - write status register 2
+ */
+ WRSR2 = 0x31,
+
RNVCR = 0xB5,
WNVCR = 0xB1,
@@ -549,7 +560,8 @@
qemu_iovec_destroy(iov);
g_free(iov);
- /* do nothing. Masters do not directly interact with the backing store,
+ /*
+ * do nothing. Masters do not directly interact with the backing store,
* only the working copy so no mutexing required.
*/
}
@@ -815,6 +827,15 @@
s->write_enable = false;
}
break;
+ case WRSR2:
+ switch (get_man(s)) {
+ case MAN_WINBOND:
+ s->quad_enable = !!(s->data[0] & 0x02);
+ break;
+ default:
+ break;
+ }
+ break;
case BRWR:
case EXTEND_ADDR_WRITE:
s->ear = s->data[0];
@@ -1274,7 +1295,31 @@
}
s->pos = 0;
break;
+ case WRSR2:
+ /*
+ * If WP# is low and status_register_write_disabled is high,
+ * status register writes are disabled.
+ * This is also called "hardware protected mode" (HPM). All other
+ * combinations of the two states are called "software protected mode"
+ * (SPM), and status register writes are permitted.
+ */
+ if ((s->wp_level == 0 && s->status_register_write_disabled)
+ || !s->write_enable) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "M25P80: Status register 2 write is disabled!\n");
+ break;
+ }
+ switch (get_man(s)) {
+ case MAN_WINBOND:
+ s->needed_bytes = 1;
+ s->state = STATE_COLLECTING_DATA;
+ s->pos = 0;
+ break;
+ default:
+ break;
+ }
+ break;
case WRDI:
s->write_enable = false;
if (get_man(s) == MAN_SST) {
@@ -1843,7 +1888,7 @@
type_register_static(&m25p80_info);
for (i = 0; i < ARRAY_SIZE(known_devices); ++i) {
- TypeInfo ti = {
+ const TypeInfo ti = {
.name = known_devices[i].part_name,
.parent = TYPE_M25P80,
.class_init = m25p80_class_init,
diff --git a/hw/block/m25p80_sfdp.c b/hw/block/m25p80_sfdp.c
index 82d84cc..a03a291 100644
--- a/hw/block/m25p80_sfdp.c
+++ b/hw/block/m25p80_sfdp.c
@@ -404,6 +404,42 @@
};
define_sfdp_read(w25q01jvq);
+static const uint8_t sfdp_w25q80bl[] = {
+ 0x53, 0x46, 0x44, 0x50, 0x05, 0x01, 0x00, 0xff,
+ 0x00, 0x05, 0x01, 0x10, 0x80, 0x00, 0x00, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xe5, 0x20, 0xf1, 0xff, 0xff, 0xff, 0x7f, 0x00,
+ 0x44, 0xeb, 0x08, 0x6b, 0x08, 0x3b, 0x42, 0xbb,
+ 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
+ 0xff, 0xff, 0x00, 0x00, 0x0c, 0x20, 0x0f, 0x52,
+ 0x10, 0xd8, 0x00, 0x00, 0x23, 0x02, 0xa6, 0x00,
+ 0x81, 0x6c, 0x14, 0xa7, 0xed, 0x61, 0x76, 0x33,
+ 0x7a, 0x75, 0x7a, 0x75, 0xf7, 0xa2, 0xd5, 0x5c,
+ 0x00, 0xf7, 0x1d, 0xff, 0xe9, 0x30, 0xc0, 0x80,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+};
+define_sfdp_read(w25q80bl);
+
/*
* Integrated Silicon Solution (ISSI)
*/
diff --git a/hw/block/m25p80_sfdp.h b/hw/block/m25p80_sfdp.h
index 89c2d8f..3578568 100644
--- a/hw/block/m25p80_sfdp.h
+++ b/hw/block/m25p80_sfdp.h
@@ -25,7 +25,7 @@
uint8_t m25p80_sfdp_w25q256(uint32_t addr);
uint8_t m25p80_sfdp_w25q512jv(uint32_t addr);
-
+uint8_t m25p80_sfdp_w25q80bl(uint32_t addr);
uint8_t m25p80_sfdp_w25q01jvq(uint32_t addr);
uint8_t m25p80_sfdp_is25wp256(uint32_t addr);
diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c
index 7175666..a5b3f45 100644
--- a/hw/gpio/aspeed_gpio.c
+++ b/hw/gpio/aspeed_gpio.c
@@ -227,6 +227,38 @@
FIELD(GPIO_INDEX_REG, COMMAND_SRC_1, 21, 1)
FIELD(GPIO_INDEX_REG, INPUT_MASK, 20, 1)
+/* AST2700 GPIO Register Address Offsets */
+REG32(GPIO_2700_DEBOUNCE_TIME_1, 0x000)
+REG32(GPIO_2700_DEBOUNCE_TIME_2, 0x004)
+REG32(GPIO_2700_DEBOUNCE_TIME_3, 0x008)
+REG32(GPIO_2700_INT_STATUS_1, 0x100)
+REG32(GPIO_2700_INT_STATUS_2, 0x104)
+REG32(GPIO_2700_INT_STATUS_3, 0x108)
+REG32(GPIO_2700_INT_STATUS_4, 0x10C)
+REG32(GPIO_2700_INT_STATUS_5, 0x110)
+REG32(GPIO_2700_INT_STATUS_6, 0x114)
+REG32(GPIO_2700_INT_STATUS_7, 0x118)
+/* GPIOA0 - GPIOAA7 Control Register */
+REG32(GPIO_A0_CONTROL, 0x180)
+ SHARED_FIELD(GPIO_CONTROL_OUT_DATA, 0, 1)
+ SHARED_FIELD(GPIO_CONTROL_DIRECTION, 1, 1)
+ SHARED_FIELD(GPIO_CONTROL_INT_ENABLE, 2, 1)
+ SHARED_FIELD(GPIO_CONTROL_INT_SENS_0, 3, 1)
+ SHARED_FIELD(GPIO_CONTROL_INT_SENS_1, 4, 1)
+ SHARED_FIELD(GPIO_CONTROL_INT_SENS_2, 5, 1)
+ SHARED_FIELD(GPIO_CONTROL_RESET_TOLERANCE, 6, 1)
+ SHARED_FIELD(GPIO_CONTROL_DEBOUNCE_1, 7, 1)
+ SHARED_FIELD(GPIO_CONTROL_DEBOUNCE_2, 8, 1)
+ SHARED_FIELD(GPIO_CONTROL_INPUT_MASK, 9, 1)
+ SHARED_FIELD(GPIO_CONTROL_BLINK_COUNTER_1, 10, 1)
+ SHARED_FIELD(GPIO_CONTROL_BLINK_COUNTER_2, 11, 1)
+ SHARED_FIELD(GPIO_CONTROL_INT_STATUS, 12, 1)
+ SHARED_FIELD(GPIO_CONTROL_IN_DATA, 13, 1)
+ SHARED_FIELD(GPIO_CONTROL_RESERVED, 14, 18)
+REG32(GPIO_AA7_CONTROL, 0x4DC)
+#define GPIO_2700_MEM_SIZE 0x4E0
+#define GPIO_2700_REG_ARRAY_SIZE (GPIO_2700_MEM_SIZE >> 2)
+
static int aspeed_evaluate_irq(GPIOSets *regs, int gpio_prev_high, int gpio)
{
uint32_t falling_edge = 0, rising_edge = 0;
@@ -340,7 +372,8 @@
value &= ~pin_mask;
}
- aspeed_gpio_update(s, &s->sets[set_idx], value, ~s->sets[set_idx].direction);
+ aspeed_gpio_update(s, &s->sets[set_idx], value,
+ ~s->sets[set_idx].direction);
}
/*
@@ -629,7 +662,6 @@
static void aspeed_gpio_write_index_mode(void *opaque, hwaddr offset,
uint64_t data, uint32_t size)
{
-
AspeedGPIOState *s = ASPEED_GPIO(opaque);
AspeedGPIOClass *agc = ASPEED_GPIO_GET_CLASS(s);
const GPIOSetProperties *props;
@@ -641,7 +673,7 @@
uint32_t pin_idx = reg_idx_number % ASPEED_GPIOS_PER_SET;
uint32_t group_idx = pin_idx / GPIOS_PER_GROUP;
uint32_t reg_value = 0;
- uint32_t cleared;
+ uint32_t pending = 0;
set = &s->sets[set_idx];
props = &agc->props[set_idx];
@@ -703,16 +735,23 @@
FIELD_EX32(data, GPIO_INDEX_REG, INT_SENS_2));
set->int_sens_2 = update_value_control_source(set, set->int_sens_2,
reg_value);
- /* set interrupt status */
- reg_value = set->int_status;
- reg_value = deposit32(reg_value, pin_idx, 1,
- FIELD_EX32(data, GPIO_INDEX_REG, INT_STATUS));
- cleared = ctpop32(reg_value & set->int_status);
- if (s->pending && cleared) {
- assert(s->pending >= cleared);
- s->pending -= cleared;
+ /* interrupt status */
+ if (FIELD_EX32(data, GPIO_INDEX_REG, INT_STATUS)) {
+ /* pending is either 1 or 0 for a 1-bit field */
+ pending = extract32(set->int_status, pin_idx, 1);
+
+ assert(s->pending >= pending);
+
+ /* No change to s->pending if pending is 0 */
+ s->pending -= pending;
+
+ /*
+ * The write acknowledged the interrupt regardless of whether it
+ * was pending or not. The post-condition is that it mustn't be
+ * pending. Unconditionally clear the status bit.
+ */
+ set->int_status = deposit32(set->int_status, pin_idx, 1, 0);
}
- set->int_status &= ~reg_value;
break;
case gpio_reg_idx_debounce:
reg_value = set->debounce_1;
@@ -963,7 +1002,317 @@
aspeed_gpio_set_pin_level(s, set_idx, pin, level);
}
-/****************** Setup functions ******************/
+static uint64_t aspeed_gpio_2700_read_control_reg(AspeedGPIOState *s,
+ uint32_t pin)
+{
+ AspeedGPIOClass *agc = ASPEED_GPIO_GET_CLASS(s);
+ GPIOSets *set;
+ uint64_t value = 0;
+ uint32_t set_idx;
+ uint32_t pin_idx;
+
+ set_idx = pin / ASPEED_GPIOS_PER_SET;
+ pin_idx = pin % ASPEED_GPIOS_PER_SET;
+
+ if (set_idx >= agc->nr_gpio_sets) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: set index: %d, out of bounds\n",
+ __func__, set_idx);
+ return 0;
+ }
+
+ set = &s->sets[set_idx];
+ value = SHARED_FIELD_DP32(value, GPIO_CONTROL_OUT_DATA,
+ extract32(set->data_read, pin_idx, 1));
+ value = SHARED_FIELD_DP32(value, GPIO_CONTROL_DIRECTION,
+ extract32(set->direction, pin_idx, 1));
+ value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INT_ENABLE,
+ extract32(set->int_enable, pin_idx, 1));
+ value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INT_SENS_0,
+ extract32(set->int_sens_0, pin_idx, 1));
+ value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INT_SENS_1,
+ extract32(set->int_sens_1, pin_idx, 1));
+ value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INT_SENS_2,
+ extract32(set->int_sens_2, pin_idx, 1));
+ value = SHARED_FIELD_DP32(value, GPIO_CONTROL_RESET_TOLERANCE,
+ extract32(set->reset_tol, pin_idx, 1));
+ value = SHARED_FIELD_DP32(value, GPIO_CONTROL_DEBOUNCE_1,
+ extract32(set->debounce_1, pin_idx, 1));
+ value = SHARED_FIELD_DP32(value, GPIO_CONTROL_DEBOUNCE_2,
+ extract32(set->debounce_2, pin_idx, 1));
+ value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INPUT_MASK,
+ extract32(set->input_mask, pin_idx, 1));
+ value = SHARED_FIELD_DP32(value, GPIO_CONTROL_INT_STATUS,
+ extract32(set->int_status, pin_idx, 1));
+ value = SHARED_FIELD_DP32(value, GPIO_CONTROL_IN_DATA,
+ extract32(set->data_value, pin_idx, 1));
+ return value;
+}
+
+static void aspeed_gpio_2700_write_control_reg(AspeedGPIOState *s,
+ uint32_t pin, uint64_t data)
+{
+ AspeedGPIOClass *agc = ASPEED_GPIO_GET_CLASS(s);
+ const GPIOSetProperties *props;
+ GPIOSets *set;
+ uint32_t set_idx;
+ uint32_t pin_idx;
+ uint32_t group_value = 0;
+ uint32_t pending = 0;
+
+ set_idx = pin / ASPEED_GPIOS_PER_SET;
+ pin_idx = pin % ASPEED_GPIOS_PER_SET;
+
+ if (set_idx >= agc->nr_gpio_sets) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: set index: %d, out of bounds\n",
+ __func__, set_idx);
+ return;
+ }
+
+ set = &s->sets[set_idx];
+ props = &agc->props[set_idx];
+
+ /* direction */
+ group_value = set->direction;
+ group_value = deposit32(group_value, pin_idx, 1,
+ SHARED_FIELD_EX32(data, GPIO_CONTROL_DIRECTION));
+ /*
+ * where data is the value attempted to be written to the pin:
+ * pin type | input mask | output mask | expected value
+ * ------------------------------------------------------------
+ * bidirectional | 1 | 1 | data
+ * input only | 1 | 0 | 0
+ * output only | 0 | 1 | 1
+ * no pin | 0 | 0 | 0
+ *
+ * which is captured by:
+ * data = ( data | ~input) & output;
+ */
+ group_value = (group_value | ~props->input) & props->output;
+ set->direction = update_value_control_source(set, set->direction,
+ group_value);
+
+ /* out data */
+ group_value = set->data_read;
+ group_value = deposit32(group_value, pin_idx, 1,
+ SHARED_FIELD_EX32(data, GPIO_CONTROL_OUT_DATA));
+ group_value &= props->output;
+ group_value = update_value_control_source(set, set->data_read,
+ group_value);
+ set->data_read = group_value;
+
+ /* interrupt enable */
+ group_value = set->int_enable;
+ group_value = deposit32(group_value, pin_idx, 1,
+ SHARED_FIELD_EX32(data, GPIO_CONTROL_INT_ENABLE));
+ set->int_enable = update_value_control_source(set, set->int_enable,
+ group_value);
+
+ /* interrupt sensitivity type 0 */
+ group_value = set->int_sens_0;
+ group_value = deposit32(group_value, pin_idx, 1,
+ SHARED_FIELD_EX32(data, GPIO_CONTROL_INT_SENS_0));
+ set->int_sens_0 = update_value_control_source(set, set->int_sens_0,
+ group_value);
+
+ /* interrupt sensitivity type 1 */
+ group_value = set->int_sens_1;
+ group_value = deposit32(group_value, pin_idx, 1,
+ SHARED_FIELD_EX32(data, GPIO_CONTROL_INT_SENS_1));
+ set->int_sens_1 = update_value_control_source(set, set->int_sens_1,
+ group_value);
+
+ /* interrupt sensitivity type 2 */
+ group_value = set->int_sens_2;
+ group_value = deposit32(group_value, pin_idx, 1,
+ SHARED_FIELD_EX32(data, GPIO_CONTROL_INT_SENS_2));
+ set->int_sens_2 = update_value_control_source(set, set->int_sens_2,
+ group_value);
+
+ /* reset tolerance enable */
+ group_value = set->reset_tol;
+ group_value = deposit32(group_value, pin_idx, 1,
+ SHARED_FIELD_EX32(data, GPIO_CONTROL_RESET_TOLERANCE));
+ set->reset_tol = update_value_control_source(set, set->reset_tol,
+ group_value);
+
+ /* debounce 1 */
+ group_value = set->debounce_1;
+ group_value = deposit32(group_value, pin_idx, 1,
+ SHARED_FIELD_EX32(data, GPIO_CONTROL_DEBOUNCE_1));
+ set->debounce_1 = update_value_control_source(set, set->debounce_1,
+ group_value);
+
+ /* debounce 2 */
+ group_value = set->debounce_2;
+ group_value = deposit32(group_value, pin_idx, 1,
+ SHARED_FIELD_EX32(data, GPIO_CONTROL_DEBOUNCE_2));
+ set->debounce_2 = update_value_control_source(set, set->debounce_2,
+ group_value);
+
+ /* input mask */
+ group_value = set->input_mask;
+ group_value = deposit32(group_value, pin_idx, 1,
+ SHARED_FIELD_EX32(data, GPIO_CONTROL_INPUT_MASK));
+ /*
+ * feeds into interrupt generation
+ * 0: read from data value reg will be updated
+ * 1: read from data value reg will not be updated
+ */
+ set->input_mask = group_value & props->input;
+
+ /* blink counter 1 */
+ /* blink counter 2 */
+ /* unimplement */
+
+ /* interrupt status */
+ if (SHARED_FIELD_EX32(data, GPIO_CONTROL_INT_STATUS)) {
+ /* pending is either 1 or 0 for a 1-bit field */
+ pending = extract32(set->int_status, pin_idx, 1);
+
+ assert(s->pending >= pending);
+
+ /* No change to s->pending if pending is 0 */
+ s->pending -= pending;
+
+ /*
+ * The write acknowledged the interrupt regardless of whether it
+ * was pending or not. The post-condition is that it mustn't be
+ * pending. Unconditionally clear the status bit.
+ */
+ set->int_status = deposit32(set->int_status, pin_idx, 1, 0);
+ }
+
+ aspeed_gpio_update(s, set, set->data_value, UINT32_MAX);
+ return;
+}
+
+static uint64_t aspeed_gpio_2700_read(void *opaque, hwaddr offset,
+ uint32_t size)
+{
+ AspeedGPIOState *s = ASPEED_GPIO(opaque);
+ AspeedGPIOClass *agc = ASPEED_GPIO_GET_CLASS(s);
+ GPIOSets *set;
+ uint64_t value;
+ uint64_t reg;
+ uint32_t pin;
+ uint32_t idx;
+
+ reg = offset >> 2;
+
+ if (reg >= agc->reg_table_count) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: offset 0x%" PRIx64 " out of bounds\n",
+ __func__, offset);
+ return 0;
+ }
+
+ switch (reg) {
+ case R_GPIO_2700_DEBOUNCE_TIME_1 ... R_GPIO_2700_DEBOUNCE_TIME_3:
+ idx = reg - R_GPIO_2700_DEBOUNCE_TIME_1;
+
+ if (idx >= ASPEED_GPIO_NR_DEBOUNCE_REGS) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: debounce index: %d, out of bounds\n",
+ __func__, idx);
+ return 0;
+ }
+
+ value = (uint64_t) s->debounce_regs[idx];
+ break;
+ case R_GPIO_2700_INT_STATUS_1 ... R_GPIO_2700_INT_STATUS_7:
+ idx = reg - R_GPIO_2700_INT_STATUS_1;
+
+ if (idx >= agc->nr_gpio_sets) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: interrupt status index: %d, out of bounds\n",
+ __func__, idx);
+ return 0;
+ }
+
+ set = &s->sets[idx];
+ value = (uint64_t) set->int_status;
+ break;
+ case R_GPIO_A0_CONTROL ... R_GPIO_AA7_CONTROL:
+ pin = reg - R_GPIO_A0_CONTROL;
+
+ if (pin >= agc->nr_gpio_pins) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid pin number: %d\n",
+ __func__, pin);
+ return 0;
+ }
+
+ value = aspeed_gpio_2700_read_control_reg(s, pin);
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: no getter for offset 0x%"
+ PRIx64"\n", __func__, offset);
+ return 0;
+ }
+
+ trace_aspeed_gpio_read(offset, value);
+ return value;
+}
+
+static void aspeed_gpio_2700_write(void *opaque, hwaddr offset,
+ uint64_t data, uint32_t size)
+{
+ AspeedGPIOState *s = ASPEED_GPIO(opaque);
+ AspeedGPIOClass *agc = ASPEED_GPIO_GET_CLASS(s);
+ uint64_t reg;
+ uint32_t pin;
+ uint32_t idx;
+
+ trace_aspeed_gpio_write(offset, data);
+
+ reg = offset >> 2;
+
+ if (reg >= agc->reg_table_count) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: offset 0x%" PRIx64 " out of bounds\n",
+ __func__, offset);
+ return;
+ }
+
+ switch (reg) {
+ case R_GPIO_2700_DEBOUNCE_TIME_1 ... R_GPIO_2700_DEBOUNCE_TIME_3:
+ idx = reg - R_GPIO_2700_DEBOUNCE_TIME_1;
+
+ if (idx >= ASPEED_GPIO_NR_DEBOUNCE_REGS) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: debounce index: %d out of bounds\n",
+ __func__, idx);
+ return;
+ }
+
+ s->debounce_regs[idx] = (uint32_t) data;
+ break;
+ case R_GPIO_A0_CONTROL ... R_GPIO_AA7_CONTROL:
+ pin = reg - R_GPIO_A0_CONTROL;
+
+ if (pin >= agc->nr_gpio_pins) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid pin number: %d\n",
+ __func__, pin);
+ return;
+ }
+
+ if (SHARED_FIELD_EX32(data, GPIO_CONTROL_RESERVED)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid reserved data: 0x%"
+ PRIx64"\n", __func__, data);
+ return;
+ }
+
+ aspeed_gpio_2700_write_control_reg(s, pin, data);
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: no setter for offset 0x%"
+ PRIx64"\n", __func__, offset);
+ break;
+ }
+
+ return;
+}
+
+/* Setup functions */
static const GPIOSetProperties ast2400_set_props[ASPEED_GPIO_MAX_NR_SETS] = {
[0] = {0xffffffff, 0xffffffff, {"A", "B", "C", "D"} },
[1] = {0xffffffff, 0xffffffff, {"E", "F", "G", "H"} },
@@ -1009,6 +1358,16 @@
[5] = {0x000000ff, 0x00000000, {"U"} },
};
+static GPIOSetProperties ast2700_set_props[ASPEED_GPIO_MAX_NR_SETS] = {
+ [0] = {0xffffffff, 0xffffffff, {"A", "B", "C", "D"} },
+ [1] = {0x0fffffff, 0x0fffffff, {"E", "F", "G", "H"} },
+ [2] = {0xffffffff, 0xffffffff, {"I", "J", "K", "L"} },
+ [3] = {0xffffffff, 0xffffffff, {"M", "N", "O", "P"} },
+ [4] = {0xffffffff, 0xffffffff, {"Q", "R", "S", "T"} },
+ [5] = {0xffffffff, 0xffffffff, {"U", "V", "W", "X"} },
+ [6] = {0x00ffffff, 0x00ffffff, {"Y", "Z", "AA"} },
+};
+
static const MemoryRegionOps aspeed_gpio_ops = {
.read = aspeed_gpio_read,
.write = aspeed_gpio_write,
@@ -1017,6 +1376,14 @@
.valid.max_access_size = 4,
};
+static const MemoryRegionOps aspeed_gpio_2700_ops = {
+ .read = aspeed_gpio_2700_read,
+ .write = aspeed_gpio_2700_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid.min_access_size = 4,
+ .valid.max_access_size = 4,
+};
+
static void aspeed_gpio_reset(DeviceState *dev)
{
AspeedGPIOState *s = ASPEED_GPIO(dev);
@@ -1046,8 +1413,8 @@
}
}
- memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_gpio_ops, s,
- TYPE_ASPEED_GPIO, 0x800);
+ memory_region_init_io(&s->iomem, OBJECT(s), agc->reg_ops, s,
+ TYPE_ASPEED_GPIO, agc->mem_size);
sysbus_init_mmio(sbd, &s->iomem);
}
@@ -1130,6 +1497,8 @@
agc->nr_gpio_sets = 7;
agc->reg_table = aspeed_3_3v_gpios;
agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
+ agc->mem_size = 0x1000;
+ agc->reg_ops = &aspeed_gpio_ops;
}
static void aspeed_gpio_2500_class_init(ObjectClass *klass, void *data)
@@ -1141,6 +1510,8 @@
agc->nr_gpio_sets = 8;
agc->reg_table = aspeed_3_3v_gpios;
agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
+ agc->mem_size = 0x1000;
+ agc->reg_ops = &aspeed_gpio_ops;
}
static void aspeed_gpio_ast2600_3_3v_class_init(ObjectClass *klass, void *data)
@@ -1152,6 +1523,8 @@
agc->nr_gpio_sets = 7;
agc->reg_table = aspeed_3_3v_gpios;
agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
+ agc->mem_size = 0x800;
+ agc->reg_ops = &aspeed_gpio_ops;
}
static void aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass, void *data)
@@ -1163,6 +1536,8 @@
agc->nr_gpio_sets = 2;
agc->reg_table = aspeed_1_8v_gpios;
agc->reg_table_count = GPIO_1_8V_REG_ARRAY_SIZE;
+ agc->mem_size = 0x800;
+ agc->reg_ops = &aspeed_gpio_ops;
}
static void aspeed_gpio_1030_class_init(ObjectClass *klass, void *data)
@@ -1174,6 +1549,20 @@
agc->nr_gpio_sets = 6;
agc->reg_table = aspeed_3_3v_gpios;
agc->reg_table_count = GPIO_3_3V_REG_ARRAY_SIZE;
+ agc->mem_size = 0x1000;
+ agc->reg_ops = &aspeed_gpio_ops;
+}
+
+static void aspeed_gpio_2700_class_init(ObjectClass *klass, void *data)
+{
+ AspeedGPIOClass *agc = ASPEED_GPIO_CLASS(klass);
+
+ agc->props = ast2700_set_props;
+ agc->nr_gpio_pins = 216;
+ agc->nr_gpio_sets = 7;
+ agc->reg_table_count = GPIO_2700_REG_ARRAY_SIZE;
+ agc->mem_size = 0x1000;
+ agc->reg_ops = &aspeed_gpio_2700_ops;
}
static const TypeInfo aspeed_gpio_info = {
@@ -1220,6 +1609,13 @@
.instance_init = aspeed_gpio_init,
};
+static const TypeInfo aspeed_gpio_ast2700_info = {
+ .name = TYPE_ASPEED_GPIO "-ast2700",
+ .parent = TYPE_ASPEED_GPIO,
+ .class_init = aspeed_gpio_2700_class_init,
+ .instance_init = aspeed_gpio_init,
+};
+
static void aspeed_gpio_register_types(void)
{
type_register_static(&aspeed_gpio_info);
@@ -1228,6 +1624,7 @@
type_register_static(&aspeed_gpio_ast2600_3_3v_info);
type_register_static(&aspeed_gpio_ast2600_1_8v_info);
type_register_static(&aspeed_gpio_ast1030_info);
+ type_register_static(&aspeed_gpio_ast2700_info);
}
type_init(aspeed_gpio_register_types);
diff --git a/hw/misc/aspeed_hace.c b/hw/misc/aspeed_hace.c
index b6f43f6..bc1d66a 100644
--- a/hw/misc/aspeed_hace.c
+++ b/hw/misc/aspeed_hace.c
@@ -1,6 +1,7 @@
/*
* ASPEED Hash and Crypto Engine
*
+ * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
* Copyright (C) 2021 IBM Corp.
*
* Joel Stanley <joel@jms.id.au>
@@ -151,49 +152,28 @@
return iov_count;
}
-/**
- * Generate iov for accumulative mode.
- *
- * @param s aspeed hace state object
- * @param iov iov of the current request
- * @param id index of the current iov
- * @param req_len length of the current request
- *
- * @return count of iov
- */
-static int gen_acc_mode_iov(AspeedHACEState *s, struct iovec *iov, int id,
- hwaddr *req_len)
-{
- uint32_t pad_offset;
- uint32_t total_msg_len;
- s->total_req_len += *req_len;
-
- if (has_padding(s, &iov[id], *req_len, &total_msg_len, &pad_offset)) {
- if (s->iov_count) {
- return reconstruct_iov(s, iov, id, &pad_offset);
- }
-
- *req_len -= s->total_req_len - total_msg_len;
- s->total_req_len = 0;
- iov[id].iov_len = *req_len;
- } else {
- s->iov_cache[s->iov_count].iov_base = iov->iov_base;
- s->iov_cache[s->iov_count].iov_len = *req_len;
- ++s->iov_count;
- }
-
- return id + 1;
-}
-
static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode,
bool acc_mode)
{
struct iovec iov[ASPEED_HACE_MAX_SG];
+ uint32_t total_msg_len;
+ uint32_t pad_offset;
g_autofree uint8_t *digest_buf = NULL;
size_t digest_len = 0;
- int niov = 0;
+ bool sg_acc_mode_final_request = false;
int i;
void *haddr;
+ Error *local_err = NULL;
+
+ if (acc_mode && s->hash_ctx == NULL) {
+ s->hash_ctx = qcrypto_hash_new(algo, &local_err);
+ if (s->hash_ctx == NULL) {
+ qemu_log_mask(LOG_GUEST_ERROR, "qcrypto hash failed : %s",
+ error_get_pretty(local_err));
+ error_free(local_err);
+ return;
+ }
+ }
if (sg_mode) {
uint32_t len = 0;
@@ -226,8 +206,16 @@
}
iov[i].iov_base = haddr;
if (acc_mode) {
- niov = gen_acc_mode_iov(s, iov, i, &plen);
+ s->total_req_len += plen;
+ if (has_padding(s, &iov[i], plen, &total_msg_len,
+ &pad_offset)) {
+ /* Padding being present indicates the final request */
+ sg_acc_mode_final_request = true;
+ iov[i].iov_len = pad_offset;
+ } else {
+ iov[i].iov_len = plen;
+ }
} else {
iov[i].iov_len = plen;
}
@@ -252,21 +240,42 @@
* required to check whether cache is empty. If no, we should
* combine cached iov and the current iov.
*/
- uint32_t total_msg_len;
- uint32_t pad_offset;
s->total_req_len += len;
if (has_padding(s, iov, len, &total_msg_len, &pad_offset)) {
- niov = reconstruct_iov(s, iov, 0, &pad_offset);
+ i = reconstruct_iov(s, iov, 0, &pad_offset);
}
}
}
- if (niov) {
- i = niov;
- }
+ if (acc_mode) {
+ if (qcrypto_hash_updatev(s->hash_ctx, iov, i, &local_err) < 0) {
+ qemu_log_mask(LOG_GUEST_ERROR, "qcrypto hash update failed : %s",
+ error_get_pretty(local_err));
+ error_free(local_err);
+ return;
+ }
- if (qcrypto_hash_bytesv(algo, iov, i, &digest_buf, &digest_len, NULL) < 0) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: qcrypto failed\n", __func__);
+ if (sg_acc_mode_final_request) {
+ if (qcrypto_hash_finalize_bytes(s->hash_ctx, &digest_buf,
+ &digest_len, &local_err)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "qcrypto hash finalize failed : %s",
+ error_get_pretty(local_err));
+ error_free(local_err);
+ local_err = NULL;
+ }
+
+ qcrypto_hash_free(s->hash_ctx);
+
+ s->hash_ctx = NULL;
+ s->iov_count = 0;
+ s->total_req_len = 0;
+ }
+ } else if (qcrypto_hash_bytesv(algo, iov, i, &digest_buf,
+ &digest_len, &local_err) < 0) {
+ qemu_log_mask(LOG_GUEST_ERROR, "qcrypto hash bytesv failed : %s",
+ error_get_pretty(local_err));
+ error_free(local_err);
return;
}
@@ -397,6 +406,11 @@
{
struct AspeedHACEState *s = ASPEED_HACE(dev);
+ if (s->hash_ctx != NULL) {
+ qcrypto_hash_free(s->hash_ctx);
+ s->hash_ctx = NULL;
+ }
+
memset(s->regs, 0, sizeof(s->regs));
s->iov_count = 0;
s->total_req_len = 0;
diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c
index e3fdc66..033cbbb 100644
--- a/hw/ssi/aspeed_smc.c
+++ b/hw/ssi/aspeed_smc.c
@@ -417,7 +417,7 @@
AspeedSMCState *s = fl->controller;
trace_aspeed_smc_flash_select(fl->cs, unselect ? "un" : "");
-
+ s->unselect = unselect;
qemu_set_irq(s->cs_lines[fl->cs], unselect);
}
@@ -677,22 +677,35 @@
static void aspeed_smc_flash_update_ctrl(AspeedSMCFlash *fl, uint32_t value)
{
AspeedSMCState *s = fl->controller;
- bool unselect;
+ bool unselect = false;
+ uint32_t old_mode;
+ uint32_t new_mode;
- /* User mode selects the CS, other modes unselect */
- unselect = (value & CTRL_CMD_MODE_MASK) != CTRL_USERMODE;
+ old_mode = s->regs[s->r_ctrl0 + fl->cs] & CTRL_CMD_MODE_MASK;
+ new_mode = value & CTRL_CMD_MODE_MASK;
- /* A change of CTRL_CE_STOP_ACTIVE from 0 to 1, unselects the CS */
- if (!(s->regs[s->r_ctrl0 + fl->cs] & CTRL_CE_STOP_ACTIVE) &&
- value & CTRL_CE_STOP_ACTIVE) {
- unselect = true;
+ if (old_mode == CTRL_USERMODE) {
+ if (new_mode != CTRL_USERMODE) {
+ unselect = true;
+ }
+
+ /* A change of CTRL_CE_STOP_ACTIVE from 0 to 1, unselects the CS */
+ if (!(s->regs[s->r_ctrl0 + fl->cs] & CTRL_CE_STOP_ACTIVE) &&
+ value & CTRL_CE_STOP_ACTIVE) {
+ unselect = true;
+ }
+ } else {
+ if (new_mode != CTRL_USERMODE) {
+ unselect = true;
+ }
}
s->regs[s->r_ctrl0 + fl->cs] = value;
- s->snoop_index = unselect ? SNOOP_OFF : SNOOP_START;
-
- aspeed_smc_flash_do_select(fl, unselect);
+ if (unselect != s->unselect) {
+ s->snoop_index = unselect ? SNOOP_OFF : SNOOP_START;
+ aspeed_smc_flash_do_select(fl, unselect);
+ }
}
static void aspeed_smc_reset(DeviceState *d)
@@ -729,6 +742,8 @@
qemu_set_irq(s->cs_lines[i], true);
}
+ s->unselect = true;
+
/* setup the default segment register values and regions for all */
for (i = 0; i < asc->cs_num_max; ++i) {
aspeed_smc_flash_set_segment_region(s, i,
@@ -1261,12 +1276,13 @@
static const VMStateDescription vmstate_aspeed_smc = {
.name = "aspeed.smc",
- .version_id = 2,
+ .version_id = 3,
.minimum_version_id = 2,
.fields = (const VMStateField[]) {
VMSTATE_UINT32_ARRAY(regs, AspeedSMCState, ASPEED_SMC_R_MAX),
VMSTATE_UINT8(snoop_index, AspeedSMCState),
VMSTATE_UINT8(snoop_dummies, AspeedSMCState),
+ VMSTATE_BOOL_V(unselect, AspeedSMCState, 3),
VMSTATE_END_OF_LIST()
}
};
diff --git a/include/hw/gpio/aspeed_gpio.h b/include/hw/gpio/aspeed_gpio.h
index 90a12ae..e1e6c54 100644
--- a/include/hw/gpio/aspeed_gpio.h
+++ b/include/hw/gpio/aspeed_gpio.h
@@ -76,6 +76,8 @@
uint32_t nr_gpio_sets;
const AspeedGPIOReg *reg_table;
unsigned reg_table_count;
+ uint64_t mem_size;
+ const MemoryRegionOps *reg_ops;
};
struct AspeedGPIOState {
@@ -88,7 +90,7 @@
qemu_irq irq;
qemu_irq gpios[ASPEED_GPIO_MAX_NR_SETS][ASPEED_GPIOS_PER_SET];
-/* Parallel GPIO Registers */
+ /* Parallel GPIO Registers */
uint32_t debounce_regs[ASPEED_GPIO_NR_DEBOUNCE_REGS];
struct GPIOSets {
uint32_t data_value; /* Reflects pin values */
diff --git a/include/hw/misc/aspeed_hace.h b/include/hw/misc/aspeed_hace.h
index ecb1b67..4af9919 100644
--- a/include/hw/misc/aspeed_hace.h
+++ b/include/hw/misc/aspeed_hace.h
@@ -1,6 +1,7 @@
/*
* ASPEED Hash and Crypto Engine
*
+ * Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
* Copyright (C) 2021 IBM Corp.
*
* SPDX-License-Identifier: GPL-2.0-or-later
@@ -10,6 +11,7 @@
#define ASPEED_HACE_H
#include "hw/sysbus.h"
+#include "crypto/hash.h"
#define TYPE_ASPEED_HACE "aspeed.hace"
#define TYPE_ASPEED_AST2400_HACE TYPE_ASPEED_HACE "-ast2400"
@@ -35,6 +37,8 @@
MemoryRegion *dram_mr;
AddressSpace dram_as;
+
+ QCryptoHash *hash_ctx;
};
diff --git a/include/hw/ssi/aspeed_smc.h b/include/hw/ssi/aspeed_smc.h
index 234dca3..25b95e7 100644
--- a/include/hw/ssi/aspeed_smc.h
+++ b/include/hw/ssi/aspeed_smc.h
@@ -82,6 +82,7 @@
uint8_t snoop_index;
uint8_t snoop_dummies;
+ bool unselect;
};
typedef struct AspeedSegments {
diff --git a/tests/avocado/machine_aspeed.py b/tests/avocado/machine_aspeed.py
index 4e144bd..241ef18 100644
--- a/tests/avocado/machine_aspeed.py
+++ b/tests/avocado/machine_aspeed.py
@@ -19,258 +19,6 @@
from avocado_qemu import has_cmd
from avocado.utils import archive
from avocado import skipUnless
-from avocado import skipUnless
-
-
-class AST1030Machine(QemuSystemTest):
- """Boots the zephyr os and checks that the console is operational"""
-
- timeout = 10
-
- def test_ast1030_zephyros_1_04(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:ast1030-evb
- :avocado: tags=os:zephyr
- """
- tar_url = ('https://github.com/AspeedTech-BMC'
- '/zephyr/releases/download/v00.01.04/ast1030-evb-demo.zip')
- tar_hash = '4c6a8ce3a8ba76ef1a65dae419ae3409343c4b20'
- tar_path = self.fetch_asset(tar_url, asset_hash=tar_hash)
- archive.extract(tar_path, self.workdir)
- kernel_file = self.workdir + "/ast1030-evb-demo/zephyr.elf"
- self.vm.set_console()
- self.vm.add_args('-kernel', kernel_file,
- '-nographic')
- self.vm.launch()
- wait_for_console_pattern(self, "Booting Zephyr OS")
- exec_command_and_wait_for_pattern(self, "help",
- "Available commands")
-
- def test_ast1030_zephyros_1_07(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:ast1030-evb
- :avocado: tags=os:zephyr
- """
- tar_url = ('https://github.com/AspeedTech-BMC'
- '/zephyr/releases/download/v00.01.07/ast1030-evb-demo.zip')
- tar_hash = '40ac87eabdcd3b3454ce5aad11fedc72a33ecda2'
- tar_path = self.fetch_asset(tar_url, asset_hash=tar_hash)
- archive.extract(tar_path, self.workdir)
- kernel_file = self.workdir + "/ast1030-evb-demo/zephyr.bin"
- self.vm.set_console()
- self.vm.add_args('-kernel', kernel_file,
- '-nographic')
- self.vm.launch()
- wait_for_console_pattern(self, "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(QemuSystemTest):
-
- timeout = 180
-
- def wait_for_console_pattern(self, success_message, vm=None):
- wait_for_console_pattern(self, success_message,
- failure_message='Kernel panic - not syncing',
- vm=vm)
-
- def do_test_arm_aspeed(self, image):
- self.vm.set_console()
- self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw',
- '-net', 'nic')
- 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")
- wait_for_console_pattern(self,
- "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 test_arm_ast2400_palmetto_openbmc_v2_9_0(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:palmetto-bmc
- """
-
- image_url = ('https://github.com/openbmc/openbmc/releases/download/2.9.0/'
- 'obmc-phosphor-image-palmetto.static.mtd')
- image_hash = ('3e13bbbc28e424865dc42f35ad672b10f2e82cdb11846bb28fa625b48beafd0d')
- image_path = self.fetch_asset(image_url, asset_hash=image_hash,
- algorithm='sha256')
-
- self.do_test_arm_aspeed(image_path)
-
- def test_arm_ast2500_romulus_openbmc_v2_9_0(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:romulus-bmc
- """
-
- image_url = ('https://github.com/openbmc/openbmc/releases/download/2.9.0/'
- 'obmc-phosphor-image-romulus.static.mtd')
- image_hash = ('820341076803f1955bc31e647a512c79f9add4f5233d0697678bab4604c7bb25')
- image_path = self.fetch_asset(image_url, asset_hash=image_hash,
- algorithm='sha256')
-
- self.do_test_arm_aspeed(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',
- '-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)
- time.sleep(0.1)
- exec_command(self, 'root')
- time.sleep(0.1)
- exec_command(self, "passw0rd")
-
- def do_test_arm_aspeed_buildroot_poweroff(self):
- exec_command_and_wait_for_pattern(self, 'poweroff',
- 'reboot: System halted');
-
- def test_arm_ast2500_evb_buildroot(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:ast2500-evb
- """
-
- image_url = ('https://github.com/legoater/qemu-aspeed-boot/raw/master/'
- 'images/ast2500-evb/buildroot-2023.11/flash.img')
- image_hash = ('c23db6160cf77d0258397eb2051162c8473a56c441417c52a91ba217186e715f')
- image_path = self.fetch_asset(image_url, asset_hash=image_hash,
- algorithm='sha256')
-
- 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', 'Aspeed AST2500 EVB')
-
- 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()
-
- def test_arm_ast2600_evb_buildroot(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:ast2600-evb
- """
-
- image_url = ('https://github.com/legoater/qemu-aspeed-boot/raw/master/'
- 'images/ast2600-evb/buildroot-2023.11/flash.img')
- image_hash = ('b62808daef48b438d0728ee07662290490ecfa65987bb91294cafb1bb7ad1a68')
- image_path = self.fetch_asset(image_url, asset_hash=image_hash,
- algorithm='sha256')
-
- 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', 'Aspeed AST2600 EVB')
-
- 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(self, 'i2cset -y 3 0x42 0x64 0x00 0xaa i');
- time.sleep(0.1)
- 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()
-
- @skipUnless(*has_cmd('swtpm'))
- def test_arm_ast2600_evb_buildroot_tpm(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:ast2600-evb
- """
-
- image_url = ('https://github.com/legoater/qemu-aspeed-boot/raw/master/'
- 'images/ast2600-evb/buildroot-2023.02-tpm/flash.img')
- image_hash = ('a46009ae8a5403a0826d607215e731a8c68d27c14c41e55331706b8f9c7bd997')
- image_path = self.fetch_asset(image_url, asset_hash=image_hash,
- algorithm='sha256')
-
- # force creation of VM object, which also defines self._sd
- vm = self.vm
-
- socket = os.path.join(self._sd.name, 'swtpm-socket')
-
- subprocess.run(['swtpm', 'socket', '-d', '--tpm2',
- '--tpmstate', f'dir={self.vm.temp_dir}',
- '--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()
class AST2x00MachineSDK(QemuSystemTest, LinuxSSHMixIn):
@@ -452,43 +200,3 @@ def test_aarch64_ast2700_evb_sdk_v09_02(self):
property='temperature', value=18000)
self.ssh_command_output_contains(
'cat /sys/class/hwmon/hwmon20/temp1_input', '18000')
-
-class AST2x00MachineMMC(QemuSystemTest):
-
- timeout = 240
-
- def wait_for_console_pattern(self, success_message, vm=None):
- wait_for_console_pattern(self, success_message,
- failure_message='Kernel panic - not syncing',
- vm=vm)
-
- def test_arm_aspeed_emmc_boot(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:rainier-bmc
- :avocado: tags=device:emmc
- """
-
- image_url = ('https://fileserver.linaro.org/s/B6pJTwWEkzSDi36/download/'
- 'mmc-p10bmc-20240617.qcow2')
- image_hash = ('d523fb478d2b84d5adc5658d08502bc64b1486955683814f89c6137518acd90b')
- image_path = self.fetch_asset(image_url, asset_hash=image_hash,
- algorithm='sha256')
-
- self.require_netdev('user')
-
- self.vm.set_console()
- self.vm.add_args('-drive',
- 'file=' + image_path + ',if=sd,id=sd2,index=2',
- '-net', 'nic', '-net', 'user')
- 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')
diff --git a/tests/functional/meson.build b/tests/functional/meson.build
index 5ccc1aa..97c1c59 100644
--- a/tests/functional/meson.build
+++ b/tests/functional/meson.build
@@ -15,6 +15,7 @@
'aarch64_sbsaref' : 600,
'aarch64_virt' : 360,
'acpi_bits' : 240,
+ 'arm_aspeed' : 600,
'arm_raspi2' : 120,
'arm_tuxrun' : 120,
'mips_malta' : 120,
@@ -51,6 +52,7 @@
]
tests_arm_system_thorough = [
+ 'arm_aspeed',
'arm_canona1100',
'arm_integratorcp',
'arm_raspi2',
diff --git a/tests/functional/test_arm_aspeed.py b/tests/functional/test_arm_aspeed.py
new file mode 100644
index 0000000..9761fc0
--- /dev/null
+++ b/tests/functional/test_arm_aspeed.py
@@ -0,0 +1,282 @@
+#!/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 exec_command
+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',
+ '-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)
+ time.sleep(0.1)
+ exec_command(self, 'root')
+ time.sleep(0.1)
+ exec_command(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',
+ 'Aspeed AST2500 EVB')
+
+ 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', 'Aspeed AST2600 EVB')
+
+ 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(self, 'i2cset -y 3 0x42 0x64 0x00 0xaa i');
+ time.sleep(0.1)
+ 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()
+
+ socket_dir = tempfile.TemporaryDirectory(prefix="qemu_")
+ socket = os.path.join(socket_dir.name, 'swtpm-socket')
+
+ subprocess.run(['swtpm', 'socket', '-d', '--tpm2',
+ '--tpmstate', f'dir={self.vm.temp_dir}',
+ '--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()
+
+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()
diff --git a/tests/qtest/aspeed_smc-test.c b/tests/qtest/aspeed_smc-test.c
index c713a37..4673371 100644
--- a/tests/qtest/aspeed_smc-test.c
+++ b/tests/qtest/aspeed_smc-test.c
@@ -353,7 +353,8 @@
uint32_t page[FLASH_PAGE_SIZE / 4];
int i;
- /* Enable 4BYTE mode for controller. This is should be strapped by
+ /*
+ * Enable 4BYTE mode for controller. This is should be strapped by
* HW for CE0 anyhow.
*/
spi_ce_ctrl(1 << CRTL_EXTENDED0);
@@ -394,7 +395,8 @@
uint32_t page[FLASH_PAGE_SIZE / 4];
int i;
- /* Enable 4BYTE mode for controller. This is should be strapped by
+ /*
+ * Enable 4BYTE mode for controller. This is should be strapped by
* HW for CE0 anyhow.
*/
spi_ce_ctrl(1 << CRTL_EXTENDED0);
diff --git a/tests/qtest/ast2700-gpio-test.c b/tests/qtest/ast2700-gpio-test.c
new file mode 100644
index 0000000..9275845
--- /dev/null
+++ b/tests/qtest/ast2700-gpio-test.c
@@ -0,0 +1,95 @@
+/*
+ * QTest testcase for the ASPEED AST2700 GPIO Controller.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright (C) 2024 ASPEED Technology Inc.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/bitops.h"
+#include "qemu/timer.h"
+#include "qapi/qmp/qdict.h"
+#include "libqtest-single.h"
+
+#define AST2700_GPIO_BASE 0x14C0B000
+#define GPIOA0_CONTROL 0x180
+
+static void test_output_pins(const char *machine, const uint32_t base)
+{
+ QTestState *s = qtest_init(machine);
+ uint32_t offset = 0;
+ uint32_t value = 0;
+ uint32_t pin = 0;
+
+ for (char c = 'A'; c <= 'D'; c++) {
+ for (int i = 0; i < 8; i++) {
+ offset = base + (pin * 4);
+
+ /* output direction and output hi */
+ qtest_writel(s, offset, 0x00000003);
+ value = qtest_readl(s, offset);
+ g_assert_cmphex(value, ==, 0x00000003);
+
+ /* output direction and output low */
+ qtest_writel(s, offset, 0x00000002);
+ value = qtest_readl(s, offset);
+ g_assert_cmphex(value, ==, 0x00000002);
+ pin++;
+ }
+ }
+
+ qtest_quit(s);
+}
+
+static void test_input_pins(const char *machine, const uint32_t base)
+{
+ QTestState *s = qtest_init(machine);
+ char name[16];
+ uint32_t offset = 0;
+ uint32_t value = 0;
+ uint32_t pin = 0;
+
+ for (char c = 'A'; c <= 'D'; c++) {
+ for (int i = 0; i < 8; i++) {
+ sprintf(name, "gpio%c%d", c, i);
+ offset = base + (pin * 4);
+ /* input direction */
+ qtest_writel(s, offset, 0);
+
+ /* set input */
+ qtest_qom_set_bool(s, "/machine/soc/gpio", name, true);
+ value = qtest_readl(s, offset);
+ g_assert_cmphex(value, ==, 0x00002000);
+
+ /* clear input */
+ qtest_qom_set_bool(s, "/machine/soc/gpio", name, false);
+ value = qtest_readl(s, offset);
+ g_assert_cmphex(value, ==, 0);
+ pin++;
+ }
+ }
+
+ qtest_quit(s);
+}
+
+static void test_2700_input_pins(void)
+{
+ test_input_pins("-machine ast2700-evb",
+ AST2700_GPIO_BASE + GPIOA0_CONTROL);
+}
+
+static void test_2700_output_pins(void)
+{
+ test_output_pins("-machine ast2700-evb",
+ AST2700_GPIO_BASE + GPIOA0_CONTROL);
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+
+ qtest_add_func("/ast2700/gpio/input_pins", test_2700_input_pins);
+ qtest_add_func("/ast2700/gpio/output_pins", test_2700_output_pins);
+
+ return g_test_run();
+}
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index e8be8b3..f7a1903 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -210,6 +210,8 @@
['aspeed_hace-test',
'aspeed_smc-test',
'aspeed_gpio-test']
+qtests_aspeed64 = \
+ ['ast2700-gpio-test']
qtests_stm32l4x5 = \
['stm32l4x5_exti-test',
@@ -248,6 +250,7 @@
(config_all_devices.has_key('CONFIG_RASPI') ? ['bcm2835-dma-test', 'bcm2835-i2c-test'] : []) + \
(config_all_accel.has_key('CONFIG_TCG') and \
config_all_devices.has_key('CONFIG_TPM_TIS_I2C') ? ['tpm-tis-i2c-test'] : []) + \
+ (config_all_devices.has_key('CONFIG_ASPEED_SOC') ? qtests_aspeed64 : []) + \
['arm-cpu-features',
'numa-test',
'boot-serial-test',