mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-06 17:23:56 -06:00
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----- 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>
This commit is contained in:
commit
cea8ac7854
18 changed files with 1001 additions and 381 deletions
|
@ -1642,8 +1642,8 @@ static void aspeed_minibmc_machine_ast1030_evb_class_init(ObjectClass *oc,
|
|||
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);
|
||||
|
|
|
@ -62,6 +62,7 @@ static const hwaddr aspeed_soc_ast2700_memmap[] = {
|
|||
[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 @@ static const int aspeed_soc_ast2700_irqmap[] = {
|
|||
[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_gic128_intcmap[] = {
|
|||
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 @@ static void aspeed_soc_ast2700_init(Object *obj)
|
|||
|
||||
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 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp)
|
|||
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);
|
||||
|
|
|
@ -61,7 +61,8 @@ typedef struct FlashPartInfo {
|
|||
*/
|
||||
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 @@ typedef struct FlashPartInfo {
|
|||
/*
|
||||
* 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 @@ static const FlashPartInfo known_devices[] = {
|
|||
|
||||
{ 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 @@ static const FlashPartInfo known_devices[] = {
|
|||
{ 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 @@ static const FlashPartInfo known_devices[] = {
|
|||
{ 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 @@ typedef enum {
|
|||
RDCR_EQIO = 0x35,
|
||||
RSTQIO = 0xf5,
|
||||
|
||||
/*
|
||||
* Winbond: 0x31 - write status register 2
|
||||
*/
|
||||
WRSR2 = 0x31,
|
||||
|
||||
RNVCR = 0xB5,
|
||||
WNVCR = 0xB1,
|
||||
|
||||
|
@ -549,7 +560,8 @@ static void blk_sync_complete(void *opaque, int ret)
|
|||
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 @@ static void complete_collecting_data(Flash *s)
|
|||
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 @@ static void decode_new_cmd(Flash *s, uint32_t value)
|
|||
}
|
||||
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 @@ static void m25p80_register_types(void)
|
|||
|
||||
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,
|
||||
|
|
|
@ -404,6 +404,42 @@ static const uint8_t sfdp_w25q01jvq[] = {
|
|||
};
|
||||
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)
|
||||
*/
|
||||
|
|
|
@ -25,7 +25,7 @@ uint8_t m25p80_sfdp_mx66l1g45g(uint32_t addr);
|
|||
|
||||
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);
|
||||
|
|
|
@ -227,6 +227,38 @@ REG32(GPIO_INDEX_REG, 0x2AC)
|
|||
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 @@ static void aspeed_gpio_set_pin_level(AspeedGPIOState *s, uint32_t set_idx,
|
|||
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 uint64_t aspeed_gpio_read(void *opaque, hwaddr offset, uint32_t size)
|
|||
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 @@ static void aspeed_gpio_write_index_mode(void *opaque, hwaddr offset,
|
|||
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 @@ static void aspeed_gpio_write_index_mode(void *opaque, hwaddr offset,
|
|||
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 @@ static void aspeed_gpio_set_pin(Object *obj, Visitor *v, const char *name,
|
|||
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 @@ static GPIOSetProperties ast1030_set_props[ASPEED_GPIO_MAX_NR_SETS] = {
|
|||
[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 @@ static const MemoryRegionOps aspeed_gpio_ops = {
|
|||
.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 @@ static void aspeed_gpio_realize(DeviceState *dev, Error **errp)
|
|||
}
|
||||
}
|
||||
|
||||
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 @@ static void aspeed_gpio_ast2400_class_init(ObjectClass *klass, void *data)
|
|||
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 @@ static void aspeed_gpio_2500_class_init(ObjectClass *klass, void *data)
|
|||
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 @@ static void aspeed_gpio_ast2600_3_3v_class_init(ObjectClass *klass, void *data)
|
|||
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 @@ static void aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass, void *data)
|
|||
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 @@ static void aspeed_gpio_1030_class_init(ObjectClass *klass, void *data)
|
|||
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 @@ static const TypeInfo aspeed_gpio_ast1030_info = {
|
|||
.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 @@ static void aspeed_gpio_register_types(void)
|
|||
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);
|
||||
|
|
|
@ -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 @@ static int reconstruct_iov(AspeedHACEState *s, struct iovec *iov, int id,
|
|||
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 @@ static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode,
|
|||
}
|
||||
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 @@ static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode,
|
|||
* 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 @@ static void aspeed_hace_reset(DeviceState *dev)
|
|||
{
|
||||
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;
|
||||
|
|
|
@ -417,7 +417,7 @@ static void aspeed_smc_flash_do_select(AspeedSMCFlash *fl, bool unselect)
|
|||
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 const MemoryRegionOps aspeed_smc_flash_ops = {
|
|||
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 @@ static void aspeed_smc_reset(DeviceState *d)
|
|||
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 void aspeed_smc_realize(DeviceState *dev, Error **errp)
|
|||
|
||||
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()
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue