aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/arm/aspeed.c146
-rw-r--r--hw/arm/aspeed_ast2600.c22
-rw-r--r--hw/arm/aspeed_soc.c23
-rw-r--r--hw/block/m25p80.c2
-rw-r--r--hw/i2c/aspeed_i2c.c5
-rw-r--r--hw/misc/aspeed_hace.c389
-rw-r--r--hw/misc/aspeed_xdma.c124
-rw-r--r--hw/misc/meson.build1
-rw-r--r--hw/ssi/aspeed_smc.c119
9 files changed, 768 insertions, 63 deletions
diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
index a17b75f494..a10909fa83 100644
--- a/hw/arm/aspeed.c
+++ b/hw/arm/aspeed.c
@@ -138,6 +138,19 @@ struct AspeedMachineState {
/* Witherspoon hardware value: 0xF10AD216 (but use romulus definition) */
#define WITHERSPOON_BMC_HW_STRAP1 ROMULUS_BMC_HW_STRAP1
+/* Quanta-Q71l hardware value */
+#define QUANTA_Q71L_BMC_HW_STRAP1 ( \
+ SCU_AST2400_HW_STRAP_DRAM_SIZE(DRAM_SIZE_128MB) | \
+ SCU_AST2400_HW_STRAP_DRAM_CONFIG(2/* DDR3 with CL=6, CWL=5 */) | \
+ SCU_AST2400_HW_STRAP_ACPI_DIS | \
+ SCU_AST2400_HW_STRAP_SET_CLK_SOURCE(AST2400_CLK_24M_IN) | \
+ SCU_HW_STRAP_VGA_CLASS_CODE | \
+ SCU_HW_STRAP_SPI_MODE(SCU_HW_STRAP_SPI_PASS_THROUGH) | \
+ SCU_AST2400_HW_STRAP_SET_CPU_AHB_RATIO(AST2400_CPU_AHB_RATIO_2_1) | \
+ SCU_HW_STRAP_SPI_WIDTH | \
+ SCU_HW_STRAP_VGA_SIZE_SET(VGA_8M_DRAM) | \
+ SCU_AST2400_HW_STRAP_BOOT_MODE(AST2400_SPI_BOOT))
+
/* AST2600 evb hardware value */
#define AST2600_EVB_HW_STRAP1 0x000000C0
#define AST2600_EVB_HW_STRAP2 0x00000003
@@ -146,6 +159,10 @@ struct AspeedMachineState {
#define TACOMA_BMC_HW_STRAP1 0x00000000
#define TACOMA_BMC_HW_STRAP2 0x00000040
+/* Rainier hardware value: (QEMU prototype) */
+#define RAINIER_BMC_HW_STRAP1 0x00000000
+#define RAINIER_BMC_HW_STRAP2 0x00000000
+
/*
* The max ram region is for firmwares that scan the address space
* with load/store to guess how much RAM the SoC has.
@@ -327,7 +344,7 @@ static void aspeed_machine_init(MachineState *machine)
object_property_set_int(OBJECT(&bmc->soc), "num-cs", amc->num_cs,
&error_abort);
object_property_set_link(OBJECT(&bmc->soc), "dram",
- OBJECT(&bmc->ram_container), &error_abort);
+ OBJECT(machine->ram), &error_abort);
if (machine->kernel_filename) {
/*
* When booting with a -kernel command line there is no u-boot
@@ -433,6 +450,34 @@ static void palmetto_bmc_i2c_init(AspeedMachineState *bmc)
object_property_set_int(OBJECT(dev), "temperature3", 110000, &error_abort);
}
+static void quanta_q71l_bmc_i2c_init(AspeedMachineState *bmc)
+{
+ AspeedSoCState *soc = &bmc->soc;
+
+ /*
+ * The quanta-q71l platform expects tmp75s which are compatible with
+ * tmp105s.
+ */
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 1), "tmp105", 0x4c);
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 1), "tmp105", 0x4e);
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 1), "tmp105", 0x4f);
+
+ /* TODO: i2c-1: Add baseboard FRU eeprom@54 24c64 */
+ /* TODO: i2c-1: Add Frontpanel FRU eeprom@57 24c64 */
+ /* TODO: Add Memory Riser i2c mux and eeproms. */
+
+ /* TODO: i2c-2: pca9546@74 */
+ /* TODO: i2c-2: pca9548@77 */
+ /* TODO: i2c-3: Add BIOS FRU eeprom@56 24c64 */
+ /* TODO: i2c-7: Add pca9546@70 */
+ /* - i2c@0: pmbus@59 */
+ /* - i2c@1: pmbus@58 */
+ /* - i2c@2: pmbus@58 */
+ /* - i2c@3: pmbus@59 */
+ /* TODO: i2c-7: Add PDB FRU eeprom@52 */
+ /* TODO: i2c-8: Add BMC FRU eeprom@50 */
+}
+
static void ast2500_evb_i2c_init(AspeedMachineState *bmc)
{
AspeedSoCState *soc = &bmc->soc;
@@ -629,6 +674,58 @@ static void g220a_bmc_i2c_init(AspeedMachineState *bmc)
eeprom_buf);
}
+static void rainier_bmc_i2c_init(AspeedMachineState *bmc)
+{
+ AspeedSoCState *soc = &bmc->soc;
+
+ /* The rainier expects a TMP275 but a TMP105 is compatible */
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 4), TYPE_TMP105,
+ 0x48);
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 4), TYPE_TMP105,
+ 0x49);
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 4), TYPE_TMP105,
+ 0x4a);
+
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 5), TYPE_TMP105,
+ 0x48);
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 5), TYPE_TMP105,
+ 0x49);
+
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 6), TYPE_TMP105,
+ 0x48);
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 6), TYPE_TMP105,
+ 0x4a);
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 6), TYPE_TMP105,
+ 0x4b);
+
+ /* Bus 7: TODO dps310@76 */
+ /* Bus 7: TODO max31785@52 */
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 7), "pca9552", 0x61);
+ /* Bus 7: TODO si7021-a20@20 */
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 7), TYPE_TMP105,
+ 0x48);
+
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 8), TYPE_TMP105,
+ 0x48);
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 8), TYPE_TMP105,
+ 0x4a);
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 8), "pca9552", 0x61);
+ /* Bus 8: ucd90320@11 */
+ /* Bus 8: ucd90320@b */
+ /* Bus 8: ucd90320@c */
+
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 9), "tmp423", 0x4c);
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 9), "tmp423", 0x4d);
+
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 10), "tmp423", 0x4c);
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 10), "tmp423", 0x4d);
+
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 11), TYPE_TMP105,
+ 0x48);
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 11), TYPE_TMP105,
+ 0x49);
+}
+
static bool aspeed_get_mmio_exec(Object *obj, Error **errp)
{
return ASPEED_MACHINE(obj)->mmio_exec;
@@ -728,6 +825,23 @@ static void aspeed_machine_palmetto_class_init(ObjectClass *oc, void *data)
aspeed_soc_num_cpus(amc->soc_name);
};
+static void aspeed_machine_quanta_q71l_class_init(ObjectClass *oc, void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+ AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
+
+ mc->desc = "Quanta-Q71l BMC (ARM926EJ-S)";
+ amc->soc_name = "ast2400-a1";
+ amc->hw_strap1 = QUANTA_Q71L_BMC_HW_STRAP1;
+ amc->fmc_model = "n25q256a";
+ amc->spi_model = "mx25l25635e";
+ amc->num_cs = 1;
+ amc->i2c_init = quanta_q71l_bmc_i2c_init;
+ mc->default_ram_size = 128 * MiB;
+ mc->default_cpus = mc->min_cpus = mc->max_cpus =
+ aspeed_soc_num_cpus(amc->soc_name);
+}
+
static void aspeed_machine_supermicrox11_bmc_class_init(ObjectClass *oc,
void *data)
{
@@ -811,6 +925,9 @@ static void aspeed_machine_swift_class_init(ObjectClass *oc, void *data)
mc->default_ram_size = 512 * MiB;
mc->default_cpus = mc->min_cpus = mc->max_cpus =
aspeed_soc_num_cpus(amc->soc_name);
+
+ mc->deprecation_reason = "redundant system. Please use a similar "
+ "OpenPOWER BMC, Witherspoon or Romulus.";
};
static void aspeed_machine_witherspoon_class_init(ObjectClass *oc, void *data)
@@ -886,6 +1003,25 @@ static void aspeed_machine_g220a_class_init(ObjectClass *oc, void *data)
aspeed_soc_num_cpus(amc->soc_name);
};
+static void aspeed_machine_rainier_class_init(ObjectClass *oc, void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+ AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
+
+ mc->desc = "IBM Rainier BMC (Cortex A7)";
+ amc->soc_name = "ast2600-a1";
+ amc->hw_strap1 = RAINIER_BMC_HW_STRAP1;
+ amc->hw_strap2 = RAINIER_BMC_HW_STRAP2;
+ amc->fmc_model = "mx66l1g45g";
+ amc->spi_model = "mx66l1g45g";
+ amc->num_cs = 2;
+ amc->macs_mask = ASPEED_MAC2_ON | ASPEED_MAC3_ON;
+ amc->i2c_init = rainier_bmc_i2c_init;
+ mc->default_ram_size = 1 * GiB;
+ mc->default_cpus = mc->min_cpus = mc->max_cpus =
+ aspeed_soc_num_cpus(amc->soc_name);
+};
+
static const TypeInfo aspeed_machine_types[] = {
{
.name = MACHINE_TYPE_NAME("palmetto-bmc"),
@@ -928,6 +1064,14 @@ static const TypeInfo aspeed_machine_types[] = {
.parent = TYPE_ASPEED_MACHINE,
.class_init = aspeed_machine_g220a_class_init,
}, {
+ .name = MACHINE_TYPE_NAME("quanta-q71l-bmc"),
+ .parent = TYPE_ASPEED_MACHINE,
+ .class_init = aspeed_machine_quanta_q71l_class_init,
+ }, {
+ .name = MACHINE_TYPE_NAME("rainier-bmc"),
+ .parent = TYPE_ASPEED_MACHINE,
+ .class_init = aspeed_machine_rainier_class_init,
+ }, {
.name = TYPE_ASPEED_MACHINE,
.parent = TYPE_MACHINE,
.instance_size = sizeof(AspeedMachineState),
diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c
index bc87e754a3..c60824bfee 100644
--- a/hw/arm/aspeed_ast2600.c
+++ b/hw/arm/aspeed_ast2600.c
@@ -42,6 +42,7 @@ static const hwaddr aspeed_soc_ast2600_memmap[] = {
[ASPEED_DEV_ETH2] = 0x1E680000,
[ASPEED_DEV_ETH4] = 0x1E690000,
[ASPEED_DEV_VIC] = 0x1E6C0000,
+ [ASPEED_DEV_HACE] = 0x1E6D0000,
[ASPEED_DEV_SDMC] = 0x1E6E0000,
[ASPEED_DEV_SCU] = 0x1E6E2000,
[ASPEED_DEV_XDMA] = 0x1E6E7000,
@@ -102,6 +103,7 @@ static const int aspeed_soc_ast2600_irqmap[] = {
[ASPEED_DEV_I2C] = 110, /* 110 -> 125 */
[ASPEED_DEV_ETH1] = 2,
[ASPEED_DEV_ETH2] = 3,
+ [ASPEED_DEV_HACE] = 4,
[ASPEED_DEV_ETH3] = 32,
[ASPEED_DEV_ETH4] = 33,
[ASPEED_DEV_KCS] = 138, /* 138 -> 142 */
@@ -185,7 +187,8 @@ static void aspeed_soc_ast2600_init(Object *obj)
object_initialize_child(obj, "mii[*]", &s->mii[i], TYPE_ASPEED_MII);
}
- object_initialize_child(obj, "xdma", &s->xdma, TYPE_ASPEED_XDMA);
+ snprintf(typename, sizeof(typename), TYPE_ASPEED_XDMA "-%s", socname);
+ object_initialize_child(obj, "xdma", &s->xdma, typename);
snprintf(typename, sizeof(typename), "aspeed.gpio-%s", socname);
object_initialize_child(obj, "gpio", &s->gpio, typename);
@@ -213,6 +216,9 @@ static void aspeed_soc_ast2600_init(Object *obj)
TYPE_SYSBUS_SDHCI);
object_initialize_child(obj, "lpc", &s->lpc, TYPE_ASPEED_LPC);
+
+ snprintf(typename, sizeof(typename), "aspeed.hace-%s", socname);
+ object_initialize_child(obj, "hace", &s->hace, typename);
}
/*
@@ -344,10 +350,6 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
/* FMC, The number of CS is set at the board level */
object_property_set_link(OBJECT(&s->fmc), "dram", OBJECT(s->dram_mr),
&error_abort);
- if (!object_property_set_int(OBJECT(&s->fmc), "sdram-base",
- sc->memmap[ASPEED_DEV_SDRAM], errp)) {
- return;
- }
if (!sysbus_realize(SYS_BUS_DEVICE(&s->fmc), errp)) {
return;
}
@@ -498,6 +500,16 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
sysbus_connect_irq(SYS_BUS_DEVICE(&s->lpc), 1 + aspeed_lpc_kcs_4,
qdev_get_gpio_in(DEVICE(&s->a7mpcore),
sc->irqmap[ASPEED_DEV_KCS] + aspeed_lpc_kcs_4));
+
+ /* HACE */
+ object_property_set_link(OBJECT(&s->hace), "dram", OBJECT(s->dram_mr),
+ &error_abort);
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->hace), errp)) {
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->hace), 0, sc->memmap[ASPEED_DEV_HACE]);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->hace), 0,
+ aspeed_soc_get_irq(s, ASPEED_DEV_HACE));
}
static void aspeed_soc_ast2600_class_init(ObjectClass *oc, void *data)
diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c
index 057d053c84..4a95d27d9d 100644
--- a/hw/arm/aspeed_soc.c
+++ b/hw/arm/aspeed_soc.c
@@ -34,6 +34,7 @@ static const hwaddr aspeed_soc_ast2400_memmap[] = {
[ASPEED_DEV_VIC] = 0x1E6C0000,
[ASPEED_DEV_SDMC] = 0x1E6E0000,
[ASPEED_DEV_SCU] = 0x1E6E2000,
+ [ASPEED_DEV_HACE] = 0x1E6E3000,
[ASPEED_DEV_XDMA] = 0x1E6E7000,
[ASPEED_DEV_VIDEO] = 0x1E700000,
[ASPEED_DEV_ADC] = 0x1E6E9000,
@@ -65,6 +66,7 @@ static const hwaddr aspeed_soc_ast2500_memmap[] = {
[ASPEED_DEV_VIC] = 0x1E6C0000,
[ASPEED_DEV_SDMC] = 0x1E6E0000,
[ASPEED_DEV_SCU] = 0x1E6E2000,
+ [ASPEED_DEV_HACE] = 0x1E6E3000,
[ASPEED_DEV_XDMA] = 0x1E6E7000,
[ASPEED_DEV_ADC] = 0x1E6E9000,
[ASPEED_DEV_VIDEO] = 0x1E700000,
@@ -117,6 +119,7 @@ static const int aspeed_soc_ast2400_irqmap[] = {
[ASPEED_DEV_ETH2] = 3,
[ASPEED_DEV_XDMA] = 6,
[ASPEED_DEV_SDHCI] = 26,
+ [ASPEED_DEV_HACE] = 4,
};
#define aspeed_soc_ast2500_irqmap aspeed_soc_ast2400_irqmap
@@ -196,7 +199,8 @@ static void aspeed_soc_init(Object *obj)
TYPE_FTGMAC100);
}
- object_initialize_child(obj, "xdma", &s->xdma, TYPE_ASPEED_XDMA);
+ snprintf(typename, sizeof(typename), TYPE_ASPEED_XDMA "-%s", socname);
+ object_initialize_child(obj, "xdma", &s->xdma, typename);
snprintf(typename, sizeof(typename), "aspeed.gpio-%s", socname);
object_initialize_child(obj, "gpio", &s->gpio, typename);
@@ -212,6 +216,9 @@ static void aspeed_soc_init(Object *obj)
}
object_initialize_child(obj, "lpc", &s->lpc, TYPE_ASPEED_LPC);
+
+ snprintf(typename, sizeof(typename), "aspeed.hace-%s", socname);
+ object_initialize_child(obj, "hace", &s->hace, typename);
}
static void aspeed_soc_realize(DeviceState *dev, Error **errp)
@@ -301,10 +308,6 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
/* FMC, The number of CS is set at the board level */
object_property_set_link(OBJECT(&s->fmc), "dram", OBJECT(s->dram_mr),
&error_abort);
- if (!object_property_set_int(OBJECT(&s->fmc), "sdram-base",
- sc->memmap[ASPEED_DEV_SDRAM], errp)) {
- return;
- }
if (!sysbus_realize(SYS_BUS_DEVICE(&s->fmc), errp)) {
return;
}
@@ -425,6 +428,16 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
sysbus_connect_irq(SYS_BUS_DEVICE(&s->lpc), 1 + aspeed_lpc_kcs_4,
qdev_get_gpio_in(DEVICE(&s->lpc), aspeed_lpc_kcs_4));
+
+ /* HACE */
+ object_property_set_link(OBJECT(&s->hace), "dram", OBJECT(s->dram_mr),
+ &error_abort);
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->hace), errp)) {
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(&s->hace), 0, sc->memmap[ASPEED_DEV_HACE]);
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->hace), 0,
+ aspeed_soc_get_irq(s, ASPEED_DEV_HACE));
}
static Property aspeed_soc_properties[] = {
DEFINE_PROP_LINK("dram", AspeedSoCState, dram_mr, TYPE_MEMORY_REGION,
diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c
index 183d3f44c2..b77503dc84 100644
--- a/hw/block/m25p80.c
+++ b/hw/block/m25p80.c
@@ -259,6 +259,8 @@ 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) },
/* Spansion -- single (large) sector size only, at least
* for the chips listed here (without boot sectors).
diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c
index 518a3f5c6f..8d276d9ed3 100644
--- a/hw/i2c/aspeed_i2c.c
+++ b/hw/i2c/aspeed_i2c.c
@@ -601,7 +601,7 @@ static void aspeed_i2c_bus_write(void *opaque, hwaddr offset,
break;
}
- bus->dma_addr = value & 0xfffffffc;
+ bus->dma_addr = value & 0x3ffffffc;
break;
case I2CD_DMA_LEN:
@@ -816,7 +816,8 @@ static void aspeed_i2c_realize(DeviceState *dev, Error **errp)
return;
}
- address_space_init(&s->dram_as, s->dram_mr, "dma-dram");
+ address_space_init(&s->dram_as, s->dram_mr,
+ TYPE_ASPEED_I2C "-dma-dram");
}
}
diff --git a/hw/misc/aspeed_hace.c b/hw/misc/aspeed_hace.c
new file mode 100644
index 0000000000..10f00e65f4
--- /dev/null
+++ b/hw/misc/aspeed_hace.c
@@ -0,0 +1,389 @@
+/*
+ * ASPEED Hash and Crypto Engine
+ *
+ * Copyright (C) 2021 IBM Corp.
+ *
+ * Joel Stanley <joel@jms.id.au>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qemu/error-report.h"
+#include "hw/misc/aspeed_hace.h"
+#include "qapi/error.h"
+#include "migration/vmstate.h"
+#include "crypto/hash.h"
+#include "hw/qdev-properties.h"
+#include "hw/irq.h"
+
+#define R_CRYPT_CMD (0x10 / 4)
+
+#define R_STATUS (0x1c / 4)
+#define HASH_IRQ BIT(9)
+#define CRYPT_IRQ BIT(12)
+#define TAG_IRQ BIT(15)
+
+#define R_HASH_SRC (0x20 / 4)
+#define R_HASH_DEST (0x24 / 4)
+#define R_HASH_SRC_LEN (0x2c / 4)
+
+#define R_HASH_CMD (0x30 / 4)
+/* Hash algorithm selection */
+#define HASH_ALGO_MASK (BIT(4) | BIT(5) | BIT(6))
+#define HASH_ALGO_MD5 0
+#define HASH_ALGO_SHA1 BIT(5)
+#define HASH_ALGO_SHA224 BIT(6)
+#define HASH_ALGO_SHA256 (BIT(4) | BIT(6))
+#define HASH_ALGO_SHA512_SERIES (BIT(5) | BIT(6))
+/* SHA512 algorithm selection */
+#define SHA512_HASH_ALGO_MASK (BIT(10) | BIT(11) | BIT(12))
+#define HASH_ALGO_SHA512_SHA512 0
+#define HASH_ALGO_SHA512_SHA384 BIT(10)
+#define HASH_ALGO_SHA512_SHA256 BIT(11)
+#define HASH_ALGO_SHA512_SHA224 (BIT(10) | BIT(11))
+/* HMAC modes */
+#define HASH_HMAC_MASK (BIT(7) | BIT(8))
+#define HASH_DIGEST 0
+#define HASH_DIGEST_HMAC BIT(7)
+#define HASH_DIGEST_ACCUM BIT(8)
+#define HASH_HMAC_KEY (BIT(7) | BIT(8))
+/* Cascaded operation modes */
+#define HASH_ONLY 0
+#define HASH_ONLY2 BIT(0)
+#define HASH_CRYPT_THEN_HASH BIT(1)
+#define HASH_HASH_THEN_CRYPT (BIT(0) | BIT(1))
+/* Other cmd bits */
+#define HASH_IRQ_EN BIT(9)
+#define HASH_SG_EN BIT(18)
+/* Scatter-gather data list */
+#define SG_LIST_LEN_SIZE 4
+#define SG_LIST_LEN_MASK 0x0FFFFFFF
+#define SG_LIST_LEN_LAST BIT(31)
+#define SG_LIST_ADDR_SIZE 4
+#define SG_LIST_ADDR_MASK 0x7FFFFFFF
+#define SG_LIST_ENTRY_SIZE (SG_LIST_LEN_SIZE + SG_LIST_ADDR_SIZE)
+#define ASPEED_HACE_MAX_SG 256 /* max number of entries */
+
+static const struct {
+ uint32_t mask;
+ QCryptoHashAlgorithm algo;
+} hash_algo_map[] = {
+ { HASH_ALGO_MD5, QCRYPTO_HASH_ALG_MD5 },
+ { HASH_ALGO_SHA1, QCRYPTO_HASH_ALG_SHA1 },
+ { HASH_ALGO_SHA224, QCRYPTO_HASH_ALG_SHA224 },
+ { HASH_ALGO_SHA256, QCRYPTO_HASH_ALG_SHA256 },
+ { HASH_ALGO_SHA512_SERIES | HASH_ALGO_SHA512_SHA512, QCRYPTO_HASH_ALG_SHA512 },
+ { HASH_ALGO_SHA512_SERIES | HASH_ALGO_SHA512_SHA384, QCRYPTO_HASH_ALG_SHA384 },
+ { HASH_ALGO_SHA512_SERIES | HASH_ALGO_SHA512_SHA256, QCRYPTO_HASH_ALG_SHA256 },
+};
+
+static int hash_algo_lookup(uint32_t reg)
+{
+ int i;
+
+ reg &= HASH_ALGO_MASK | SHA512_HASH_ALGO_MASK;
+
+ for (i = 0; i < ARRAY_SIZE(hash_algo_map); i++) {
+ if (reg == hash_algo_map[i].mask) {
+ return hash_algo_map[i].algo;
+ }
+ }
+
+ return -1;
+}
+
+static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode)
+{
+ struct iovec iov[ASPEED_HACE_MAX_SG];
+ g_autofree uint8_t *digest_buf;
+ size_t digest_len = 0;
+ int i;
+
+ if (sg_mode) {
+ uint32_t len = 0;
+
+ for (i = 0; !(len & SG_LIST_LEN_LAST); i++) {
+ uint32_t addr, src;
+ hwaddr plen;
+
+ if (i == ASPEED_HACE_MAX_SG) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "aspeed_hace: guest failed to set end of sg list marker\n");
+ break;
+ }
+
+ src = s->regs[R_HASH_SRC] + (i * SG_LIST_ENTRY_SIZE);
+
+ len = address_space_ldl_le(&s->dram_as, src,
+ MEMTXATTRS_UNSPECIFIED, NULL);
+
+ addr = address_space_ldl_le(&s->dram_as, src + SG_LIST_LEN_SIZE,
+ MEMTXATTRS_UNSPECIFIED, NULL);
+ addr &= SG_LIST_ADDR_MASK;
+
+ iov[i].iov_len = len & SG_LIST_LEN_MASK;
+ plen = iov[i].iov_len;
+ iov[i].iov_base = address_space_map(&s->dram_as, addr, &plen, false,
+ MEMTXATTRS_UNSPECIFIED);
+ }
+ } else {
+ hwaddr len = s->regs[R_HASH_SRC_LEN];
+
+ iov[0].iov_len = len;
+ iov[0].iov_base = address_space_map(&s->dram_as, s->regs[R_HASH_SRC],
+ &len, false,
+ MEMTXATTRS_UNSPECIFIED);
+ i = 1;
+ }
+
+ if (qcrypto_hash_bytesv(algo, iov, i, &digest_buf, &digest_len, NULL) < 0) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: qcrypto failed\n", __func__);
+ return;
+ }
+
+ if (address_space_write(&s->dram_as, s->regs[R_HASH_DEST],
+ MEMTXATTRS_UNSPECIFIED,
+ digest_buf, digest_len)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "aspeed_hace: address space write failed\n");
+ }
+
+ for (; i > 0; i--) {
+ address_space_unmap(&s->dram_as, iov[i - 1].iov_base,
+ iov[i - 1].iov_len, false,
+ iov[i - 1].iov_len);
+ }
+
+ /*
+ * Set status bits to indicate completion. Testing shows hardware sets
+ * these irrespective of HASH_IRQ_EN.
+ */
+ s->regs[R_STATUS] |= HASH_IRQ;
+}
+
+static uint64_t aspeed_hace_read(void *opaque, hwaddr addr, unsigned int size)
+{
+ AspeedHACEState *s = ASPEED_HACE(opaque);
+
+ addr >>= 2;
+
+ if (addr >= ASPEED_HACE_NR_REGS) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
+ __func__, addr << 2);
+ return 0;
+ }
+
+ return s->regs[addr];
+}
+
+static void aspeed_hace_write(void *opaque, hwaddr addr, uint64_t data,
+ unsigned int size)
+{
+ AspeedHACEState *s = ASPEED_HACE(opaque);
+ AspeedHACEClass *ahc = ASPEED_HACE_GET_CLASS(s);
+
+ addr >>= 2;
+
+ if (addr >= ASPEED_HACE_NR_REGS) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
+ __func__, addr << 2);
+ return;
+ }
+
+ switch (addr) {
+ case R_STATUS:
+ if (data & HASH_IRQ) {
+ data &= ~HASH_IRQ;
+
+ if (s->regs[addr] & HASH_IRQ) {
+ qemu_irq_lower(s->irq);
+ }
+ }
+ break;
+ case R_HASH_SRC:
+ data &= ahc->src_mask;
+ break;
+ case R_HASH_DEST:
+ data &= ahc->dest_mask;
+ break;
+ case R_HASH_SRC_LEN:
+ data &= 0x0FFFFFFF;
+ break;
+ case R_HASH_CMD: {
+ int algo;
+ data &= ahc->hash_mask;
+
+ if ((data & HASH_HMAC_MASK)) {
+ qemu_log_mask(LOG_UNIMP,
+ "%s: HMAC engine command mode %"PRIx64" not implemented",
+ __func__, (data & HASH_HMAC_MASK) >> 8);
+ }
+ if (data & BIT(1)) {
+ qemu_log_mask(LOG_UNIMP,
+ "%s: Cascaded mode not implemented",
+ __func__);
+ }
+ algo = hash_algo_lookup(data);
+ if (algo < 0) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Invalid hash algorithm selection 0x%"PRIx64"\n",
+ __func__, data & ahc->hash_mask);
+ break;
+ }
+ do_hash_operation(s, algo, data & HASH_SG_EN);
+
+ if (data & HASH_IRQ_EN) {
+ qemu_irq_raise(s->irq);
+ }
+ break;
+ }
+ case R_CRYPT_CMD:
+ qemu_log_mask(LOG_UNIMP, "%s: Crypt commands not implemented\n",
+ __func__);
+ break;
+ default:
+ break;
+ }
+
+ s->regs[addr] = data;
+}
+
+static const MemoryRegionOps aspeed_hace_ops = {
+ .read = aspeed_hace_read,
+ .write = aspeed_hace_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 1,
+ .max_access_size = 4,
+ },
+};
+
+static void aspeed_hace_reset(DeviceState *dev)
+{
+ struct AspeedHACEState *s = ASPEED_HACE(dev);
+
+ memset(s->regs, 0, sizeof(s->regs));
+}
+
+static void aspeed_hace_realize(DeviceState *dev, Error **errp)
+{
+ AspeedHACEState *s = ASPEED_HACE(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+
+ sysbus_init_irq(sbd, &s->irq);
+
+ memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_hace_ops, s,
+ TYPE_ASPEED_HACE, 0x1000);
+
+ if (!s->dram_mr) {
+ error_setg(errp, TYPE_ASPEED_HACE ": 'dram' link not set");
+ return;
+ }
+
+ address_space_init(&s->dram_as, s->dram_mr, "dram");
+
+ sysbus_init_mmio(sbd, &s->iomem);
+}
+
+static Property aspeed_hace_properties[] = {
+ DEFINE_PROP_LINK("dram", AspeedHACEState, dram_mr,
+ TYPE_MEMORY_REGION, MemoryRegion *),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+
+static const VMStateDescription vmstate_aspeed_hace = {
+ .name = TYPE_ASPEED_HACE,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32_ARRAY(regs, AspeedHACEState, ASPEED_HACE_NR_REGS),
+ VMSTATE_END_OF_LIST(),
+ }
+};
+
+static void aspeed_hace_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = aspeed_hace_realize;
+ dc->reset = aspeed_hace_reset;
+ device_class_set_props(dc, aspeed_hace_properties);
+ dc->vmsd = &vmstate_aspeed_hace;
+}
+
+static const TypeInfo aspeed_hace_info = {
+ .name = TYPE_ASPEED_HACE,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(AspeedHACEState),
+ .class_init = aspeed_hace_class_init,
+ .class_size = sizeof(AspeedHACEClass)
+};
+
+static void aspeed_ast2400_hace_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedHACEClass *ahc = ASPEED_HACE_CLASS(klass);
+
+ dc->desc = "AST2400 Hash and Crypto Engine";
+
+ ahc->src_mask = 0x0FFFFFFF;
+ ahc->dest_mask = 0x0FFFFFF8;
+ ahc->hash_mask = 0x000003ff; /* No SG or SHA512 modes */
+}
+
+static const TypeInfo aspeed_ast2400_hace_info = {
+ .name = TYPE_ASPEED_AST2400_HACE,
+ .parent = TYPE_ASPEED_HACE,
+ .class_init = aspeed_ast2400_hace_class_init,
+};
+
+static void aspeed_ast2500_hace_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedHACEClass *ahc = ASPEED_HACE_CLASS(klass);
+
+ dc->desc = "AST2500 Hash and Crypto Engine";
+
+ ahc->src_mask = 0x3fffffff;
+ ahc->dest_mask = 0x3ffffff8;
+ ahc->hash_mask = 0x000003ff; /* No SG or SHA512 modes */
+}
+
+static const TypeInfo aspeed_ast2500_hace_info = {
+ .name = TYPE_ASPEED_AST2500_HACE,
+ .parent = TYPE_ASPEED_HACE,
+ .class_init = aspeed_ast2500_hace_class_init,
+};
+
+static void aspeed_ast2600_hace_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedHACEClass *ahc = ASPEED_HACE_CLASS(klass);
+
+ dc->desc = "AST2600 Hash and Crypto Engine";
+
+ ahc->src_mask = 0x7FFFFFFF;
+ ahc->dest_mask = 0x7FFFFFF8;
+ ahc->hash_mask = 0x00147FFF;
+}
+
+static const TypeInfo aspeed_ast2600_hace_info = {
+ .name = TYPE_ASPEED_AST2600_HACE,
+ .parent = TYPE_ASPEED_HACE,
+ .class_init = aspeed_ast2600_hace_class_init,
+};
+
+static void aspeed_hace_register_types(void)
+{
+ type_register_static(&aspeed_ast2400_hace_info);
+ type_register_static(&aspeed_ast2500_hace_info);
+ type_register_static(&aspeed_ast2600_hace_info);
+ type_register_static(&aspeed_hace_info);
+}
+
+type_init(aspeed_hace_register_types);
diff --git a/hw/misc/aspeed_xdma.c b/hw/misc/aspeed_xdma.c
index 533d237e3c..1c21577c98 100644
--- a/hw/misc/aspeed_xdma.c
+++ b/hw/misc/aspeed_xdma.c
@@ -30,6 +30,19 @@
#define XDMA_IRQ_ENG_STAT_US_COMP BIT(4)
#define XDMA_IRQ_ENG_STAT_DS_COMP BIT(5)
#define XDMA_IRQ_ENG_STAT_RESET 0xF8000000
+
+#define XDMA_AST2600_BMC_CMDQ_ADDR 0x14
+#define XDMA_AST2600_BMC_CMDQ_ENDP 0x18
+#define XDMA_AST2600_BMC_CMDQ_WRP 0x1c
+#define XDMA_AST2600_BMC_CMDQ_RDP 0x20
+#define XDMA_AST2600_IRQ_CTRL 0x38
+#define XDMA_AST2600_IRQ_CTRL_US_COMP BIT(16)
+#define XDMA_AST2600_IRQ_CTRL_DS_COMP BIT(17)
+#define XDMA_AST2600_IRQ_CTRL_W_MASK 0x017003FF
+#define XDMA_AST2600_IRQ_STATUS 0x3c
+#define XDMA_AST2600_IRQ_STATUS_US_COMP BIT(16)
+#define XDMA_AST2600_IRQ_STATUS_DS_COMP BIT(17)
+
#define XDMA_MEM_SIZE 0x1000
#define TO_REG(addr) ((addr) / sizeof(uint32_t))
@@ -52,56 +65,48 @@ static void aspeed_xdma_write(void *opaque, hwaddr addr, uint64_t val,
unsigned int idx;
uint32_t val32 = (uint32_t)val;
AspeedXDMAState *xdma = opaque;
+ AspeedXDMAClass *axc = ASPEED_XDMA_GET_CLASS(xdma);
if (addr >= ASPEED_XDMA_REG_SIZE) {
return;
}
- switch (addr) {
- case XDMA_BMC_CMDQ_ENDP:
+ if (addr == axc->cmdq_endp) {
xdma->regs[TO_REG(addr)] = val32 & XDMA_BMC_CMDQ_W_MASK;
- break;
- case XDMA_BMC_CMDQ_WRP:
+ } else if (addr == axc->cmdq_wrp) {
idx = TO_REG(addr);
xdma->regs[idx] = val32 & XDMA_BMC_CMDQ_W_MASK;
- xdma->regs[TO_REG(XDMA_BMC_CMDQ_RDP)] = xdma->regs[idx];
+ xdma->regs[TO_REG(axc->cmdq_rdp)] = xdma->regs[idx];
trace_aspeed_xdma_write(addr, val);
if (xdma->bmc_cmdq_readp_set) {
xdma->bmc_cmdq_readp_set = 0;
} else {
- xdma->regs[TO_REG(XDMA_IRQ_ENG_STAT)] |=
- XDMA_IRQ_ENG_STAT_US_COMP | XDMA_IRQ_ENG_STAT_DS_COMP;
+ xdma->regs[TO_REG(axc->intr_status)] |= axc->intr_complete;
- if (xdma->regs[TO_REG(XDMA_IRQ_ENG_CTRL)] &
- (XDMA_IRQ_ENG_CTRL_US_COMP | XDMA_IRQ_ENG_CTRL_DS_COMP))
+ if (xdma->regs[TO_REG(axc->intr_ctrl)] & axc->intr_complete) {
qemu_irq_raise(xdma->irq);
+ }
}
- break;
- case XDMA_BMC_CMDQ_RDP:
+ } else if (addr == axc->cmdq_rdp) {
trace_aspeed_xdma_write(addr, val);
if (val32 == XDMA_BMC_CMDQ_RDP_MAGIC) {
xdma->bmc_cmdq_readp_set = 1;
}
- break;
- case XDMA_IRQ_ENG_CTRL:
- xdma->regs[TO_REG(addr)] = val32 & XDMA_IRQ_ENG_CTRL_W_MASK;
- break;
- case XDMA_IRQ_ENG_STAT:
+ } else if (addr == axc->intr_ctrl) {
+ xdma->regs[TO_REG(addr)] = val32 & axc->intr_ctrl_mask;
+ } else if (addr == axc->intr_status) {
trace_aspeed_xdma_write(addr, val);
idx = TO_REG(addr);
- if (val32 & (XDMA_IRQ_ENG_STAT_US_COMP | XDMA_IRQ_ENG_STAT_DS_COMP)) {
- xdma->regs[idx] &=
- ~(XDMA_IRQ_ENG_STAT_US_COMP | XDMA_IRQ_ENG_STAT_DS_COMP);
+ if (val32 & axc->intr_complete) {
+ xdma->regs[idx] &= ~axc->intr_complete;
qemu_irq_lower(xdma->irq);
}
- break;
- default:
+ } else {
xdma->regs[TO_REG(addr)] = val32;
- break;
}
}
@@ -127,10 +132,11 @@ static void aspeed_xdma_realize(DeviceState *dev, Error **errp)
static void aspeed_xdma_reset(DeviceState *dev)
{
AspeedXDMAState *xdma = ASPEED_XDMA(dev);
+ AspeedXDMAClass *axc = ASPEED_XDMA_GET_CLASS(xdma);
xdma->bmc_cmdq_readp_set = 0;
memset(xdma->regs, 0, ASPEED_XDMA_REG_SIZE);
- xdma->regs[TO_REG(XDMA_IRQ_ENG_STAT)] = XDMA_IRQ_ENG_STAT_RESET;
+ xdma->regs[TO_REG(axc->intr_status)] = XDMA_IRQ_ENG_STAT_RESET;
qemu_irq_lower(xdma->irq);
}
@@ -144,6 +150,73 @@ static const VMStateDescription aspeed_xdma_vmstate = {
},
};
+static void aspeed_2600_xdma_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedXDMAClass *axc = ASPEED_XDMA_CLASS(klass);
+
+ dc->desc = "ASPEED 2600 XDMA Controller";
+
+ axc->cmdq_endp = XDMA_AST2600_BMC_CMDQ_ENDP;
+ axc->cmdq_wrp = XDMA_AST2600_BMC_CMDQ_WRP;
+ axc->cmdq_rdp = XDMA_AST2600_BMC_CMDQ_RDP;
+ axc->intr_ctrl = XDMA_AST2600_IRQ_CTRL;
+ axc->intr_ctrl_mask = XDMA_AST2600_IRQ_CTRL_W_MASK;
+ axc->intr_status = XDMA_AST2600_IRQ_STATUS;
+ axc->intr_complete = XDMA_AST2600_IRQ_STATUS_US_COMP |
+ XDMA_AST2600_IRQ_STATUS_DS_COMP;
+}
+
+static const TypeInfo aspeed_2600_xdma_info = {
+ .name = TYPE_ASPEED_2600_XDMA,
+ .parent = TYPE_ASPEED_XDMA,
+ .class_init = aspeed_2600_xdma_class_init,
+};
+
+static void aspeed_2500_xdma_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedXDMAClass *axc = ASPEED_XDMA_CLASS(klass);
+
+ dc->desc = "ASPEED 2500 XDMA Controller";
+
+ axc->cmdq_endp = XDMA_BMC_CMDQ_ENDP;
+ axc->cmdq_wrp = XDMA_BMC_CMDQ_WRP;
+ axc->cmdq_rdp = XDMA_BMC_CMDQ_RDP;
+ axc->intr_ctrl = XDMA_IRQ_ENG_CTRL;
+ axc->intr_ctrl_mask = XDMA_IRQ_ENG_CTRL_W_MASK;
+ axc->intr_status = XDMA_IRQ_ENG_STAT;
+ axc->intr_complete = XDMA_IRQ_ENG_STAT_US_COMP | XDMA_IRQ_ENG_STAT_DS_COMP;
+};
+
+static const TypeInfo aspeed_2500_xdma_info = {
+ .name = TYPE_ASPEED_2500_XDMA,
+ .parent = TYPE_ASPEED_XDMA,
+ .class_init = aspeed_2500_xdma_class_init,
+};
+
+static void aspeed_2400_xdma_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedXDMAClass *axc = ASPEED_XDMA_CLASS(klass);
+
+ dc->desc = "ASPEED 2400 XDMA Controller";
+
+ axc->cmdq_endp = XDMA_BMC_CMDQ_ENDP;
+ axc->cmdq_wrp = XDMA_BMC_CMDQ_WRP;
+ axc->cmdq_rdp = XDMA_BMC_CMDQ_RDP;
+ axc->intr_ctrl = XDMA_IRQ_ENG_CTRL;
+ axc->intr_ctrl_mask = XDMA_IRQ_ENG_CTRL_W_MASK;
+ axc->intr_status = XDMA_IRQ_ENG_STAT;
+ axc->intr_complete = XDMA_IRQ_ENG_STAT_US_COMP | XDMA_IRQ_ENG_STAT_DS_COMP;
+};
+
+static const TypeInfo aspeed_2400_xdma_info = {
+ .name = TYPE_ASPEED_2400_XDMA,
+ .parent = TYPE_ASPEED_XDMA,
+ .class_init = aspeed_2400_xdma_class_init,
+};
+
static void aspeed_xdma_class_init(ObjectClass *classp, void *data)
{
DeviceClass *dc = DEVICE_CLASS(classp);
@@ -158,10 +231,15 @@ static const TypeInfo aspeed_xdma_info = {
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(AspeedXDMAState),
.class_init = aspeed_xdma_class_init,
+ .class_size = sizeof(AspeedXDMAClass),
+ .abstract = true,
};
static void aspeed_xdma_register_type(void)
{
type_register_static(&aspeed_xdma_info);
+ type_register_static(&aspeed_2400_xdma_info);
+ type_register_static(&aspeed_2500_xdma_info);
+ type_register_static(&aspeed_2600_xdma_info);
}
type_init(aspeed_xdma_register_type);
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
index 21034dc60a..1e7b8b064b 100644
--- a/hw/misc/meson.build
+++ b/hw/misc/meson.build
@@ -109,6 +109,7 @@ softmmu_ss.add(when: 'CONFIG_PVPANIC_ISA', if_true: files('pvpanic-isa.c'))
softmmu_ss.add(when: 'CONFIG_PVPANIC_PCI', if_true: files('pvpanic-pci.c'))
softmmu_ss.add(when: 'CONFIG_AUX', if_true: files('auxbus.c'))
softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files(
+ 'aspeed_hace.c',
'aspeed_lpc.c',
'aspeed_scu.c',
'aspeed_sdmc.c',
diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c
index 16addee4dc..189b35637c 100644
--- a/hw/ssi/aspeed_smc.c
+++ b/hw/ssi/aspeed_smc.c
@@ -127,6 +127,8 @@
/* DMA Control/Status Register */
#define R_DMA_CTRL (0x80 / 4)
+#define DMA_CTRL_REQUEST (1 << 31)
+#define DMA_CTRL_GRANT (1 << 30)
#define DMA_CTRL_DELAY_MASK 0xf
#define DMA_CTRL_DELAY_SHIFT 8
#define DMA_CTRL_FREQ_MASK 0xf
@@ -178,10 +180,8 @@
* 0: 4 bytes
* 0x7FFFFF: 32M bytes
*/
-#define DMA_DRAM_ADDR(s, val) ((s)->sdram_base | \
- ((val) & (s)->ctrl->dma_dram_mask))
-#define DMA_FLASH_ADDR(s, val) ((s)->ctrl->flash_window_base | \
- ((val) & (s)->ctrl->dma_flash_mask))
+#define DMA_DRAM_ADDR(s, val) ((val) & (s)->ctrl->dma_dram_mask)
+#define DMA_FLASH_ADDR(s, val) ((val) & (s)->ctrl->dma_flash_mask)
#define DMA_LENGTH(val) ((val) & 0x01FFFFFC)
/* Flash opcodes. */
@@ -230,6 +230,7 @@ static uint32_t aspeed_smc_segment_to_reg(const AspeedSMCState *s,
const AspeedSegments *seg);
static void aspeed_smc_reg_to_segment(const AspeedSMCState *s, uint32_t reg,
AspeedSegments *seg);
+static void aspeed_smc_dma_ctrl(AspeedSMCState *s, uint32_t value);
/*
* AST2600 definitions
@@ -259,6 +260,15 @@ static uint32_t aspeed_2600_smc_segment_to_reg(const AspeedSMCState *s,
const AspeedSegments *seg);
static void aspeed_2600_smc_reg_to_segment(const AspeedSMCState *s,
uint32_t reg, AspeedSegments *seg);
+static void aspeed_2600_smc_dma_ctrl(AspeedSMCState *s, uint32_t value);
+
+#define ASPEED_SMC_FEATURE_DMA 0x1
+#define ASPEED_SMC_FEATURE_DMA_GRANT 0x2
+
+static inline bool aspeed_smc_has_dma(const AspeedSMCState *s)
+{
+ return !!(s->ctrl->features & ASPEED_SMC_FEATURE_DMA);
+}
static const AspeedSMCController controllers[] = {
{
@@ -273,10 +283,11 @@ static const AspeedSMCController controllers[] = {
.segments = aspeed_segments_legacy,
.flash_window_base = ASPEED_SOC_SMC_FLASH_BASE,
.flash_window_size = 0x6000000,
- .has_dma = false,
+ .features = 0x0,
.nregs = ASPEED_SMC_R_SMC_MAX,
.segment_to_reg = aspeed_smc_segment_to_reg,
.reg_to_segment = aspeed_smc_reg_to_segment,
+ .dma_ctrl = aspeed_smc_dma_ctrl,
}, {
.name = "aspeed.fmc-ast2400",
.r_conf = R_CONF,
@@ -289,12 +300,13 @@ static const AspeedSMCController controllers[] = {
.segments = aspeed_segments_fmc,
.flash_window_base = ASPEED_SOC_FMC_FLASH_BASE,
.flash_window_size = 0x10000000,
- .has_dma = true,
+ .features = ASPEED_SMC_FEATURE_DMA,
.dma_flash_mask = 0x0FFFFFFC,
.dma_dram_mask = 0x1FFFFFFC,
.nregs = ASPEED_SMC_R_MAX,
.segment_to_reg = aspeed_smc_segment_to_reg,
.reg_to_segment = aspeed_smc_reg_to_segment,
+ .dma_ctrl = aspeed_smc_dma_ctrl,
}, {
.name = "aspeed.spi1-ast2400",
.r_conf = R_SPI_CONF,
@@ -307,10 +319,11 @@ static const AspeedSMCController controllers[] = {
.segments = aspeed_segments_spi,
.flash_window_base = ASPEED_SOC_SPI_FLASH_BASE,
.flash_window_size = 0x10000000,
- .has_dma = false,
+ .features = 0x0,
.nregs = ASPEED_SMC_R_SPI_MAX,
.segment_to_reg = aspeed_smc_segment_to_reg,
.reg_to_segment = aspeed_smc_reg_to_segment,
+ .dma_ctrl = aspeed_smc_dma_ctrl,
}, {
.name = "aspeed.fmc-ast2500",
.r_conf = R_CONF,
@@ -323,12 +336,13 @@ static const AspeedSMCController controllers[] = {
.segments = aspeed_segments_ast2500_fmc,
.flash_window_base = ASPEED_SOC_FMC_FLASH_BASE,
.flash_window_size = 0x10000000,
- .has_dma = true,
+ .features = ASPEED_SMC_FEATURE_DMA,
.dma_flash_mask = 0x0FFFFFFC,
.dma_dram_mask = 0x3FFFFFFC,
.nregs = ASPEED_SMC_R_MAX,
.segment_to_reg = aspeed_smc_segment_to_reg,
.reg_to_segment = aspeed_smc_reg_to_segment,
+ .dma_ctrl = aspeed_smc_dma_ctrl,
}, {
.name = "aspeed.spi1-ast2500",
.r_conf = R_CONF,
@@ -341,10 +355,11 @@ static const AspeedSMCController controllers[] = {
.segments = aspeed_segments_ast2500_spi1,
.flash_window_base = ASPEED_SOC_SPI_FLASH_BASE,
.flash_window_size = 0x8000000,
- .has_dma = false,
+ .features = 0x0,
.nregs = ASPEED_SMC_R_MAX,
.segment_to_reg = aspeed_smc_segment_to_reg,
.reg_to_segment = aspeed_smc_reg_to_segment,
+ .dma_ctrl = aspeed_smc_dma_ctrl,
}, {
.name = "aspeed.spi2-ast2500",
.r_conf = R_CONF,
@@ -357,10 +372,11 @@ static const AspeedSMCController controllers[] = {
.segments = aspeed_segments_ast2500_spi2,
.flash_window_base = ASPEED_SOC_SPI2_FLASH_BASE,
.flash_window_size = 0x8000000,
- .has_dma = false,
+ .features = 0x0,
.nregs = ASPEED_SMC_R_MAX,
.segment_to_reg = aspeed_smc_segment_to_reg,
.reg_to_segment = aspeed_smc_reg_to_segment,
+ .dma_ctrl = aspeed_smc_dma_ctrl,
}, {
.name = "aspeed.fmc-ast2600",
.r_conf = R_CONF,
@@ -373,12 +389,13 @@ static const AspeedSMCController controllers[] = {
.segments = aspeed_segments_ast2600_fmc,
.flash_window_base = ASPEED26_SOC_FMC_FLASH_BASE,
.flash_window_size = 0x10000000,
- .has_dma = true,
+ .features = ASPEED_SMC_FEATURE_DMA,
.dma_flash_mask = 0x0FFFFFFC,
.dma_dram_mask = 0x3FFFFFFC,
.nregs = ASPEED_SMC_R_MAX,
.segment_to_reg = aspeed_2600_smc_segment_to_reg,
.reg_to_segment = aspeed_2600_smc_reg_to_segment,
+ .dma_ctrl = aspeed_2600_smc_dma_ctrl,
}, {
.name = "aspeed.spi1-ast2600",
.r_conf = R_CONF,
@@ -391,12 +408,14 @@ static const AspeedSMCController controllers[] = {
.segments = aspeed_segments_ast2600_spi1,
.flash_window_base = ASPEED26_SOC_SPI_FLASH_BASE,
.flash_window_size = 0x10000000,
- .has_dma = true,
+ .features = ASPEED_SMC_FEATURE_DMA |
+ ASPEED_SMC_FEATURE_DMA_GRANT,
.dma_flash_mask = 0x0FFFFFFC,
.dma_dram_mask = 0x3FFFFFFC,
.nregs = ASPEED_SMC_R_MAX,
.segment_to_reg = aspeed_2600_smc_segment_to_reg,
.reg_to_segment = aspeed_2600_smc_reg_to_segment,
+ .dma_ctrl = aspeed_2600_smc_dma_ctrl,
}, {
.name = "aspeed.spi2-ast2600",
.r_conf = R_CONF,
@@ -409,12 +428,14 @@ static const AspeedSMCController controllers[] = {
.segments = aspeed_segments_ast2600_spi2,
.flash_window_base = ASPEED26_SOC_SPI2_FLASH_BASE,
.flash_window_size = 0x10000000,
- .has_dma = true,
+ .features = ASPEED_SMC_FEATURE_DMA |
+ ASPEED_SMC_FEATURE_DMA_GRANT,
.dma_flash_mask = 0x0FFFFFFC,
.dma_dram_mask = 0x3FFFFFFC,
.nregs = ASPEED_SMC_R_MAX,
.segment_to_reg = aspeed_2600_smc_segment_to_reg,
.reg_to_segment = aspeed_2600_smc_reg_to_segment,
+ .dma_ctrl = aspeed_2600_smc_dma_ctrl,
},
};
@@ -999,11 +1020,11 @@ static uint64_t aspeed_smc_read(void *opaque, hwaddr addr, unsigned int size)
addr == R_CE_CMD_CTRL ||
addr == R_INTR_CTRL ||
addr == R_DUMMY_DATA ||
- (s->ctrl->has_dma && addr == R_DMA_CTRL) ||
- (s->ctrl->has_dma && addr == R_DMA_FLASH_ADDR) ||
- (s->ctrl->has_dma && addr == R_DMA_DRAM_ADDR) ||
- (s->ctrl->has_dma && addr == R_DMA_LEN) ||
- (s->ctrl->has_dma && addr == R_DMA_CHECKSUM) ||
+ (aspeed_smc_has_dma(s) && addr == R_DMA_CTRL) ||
+ (aspeed_smc_has_dma(s) && addr == R_DMA_FLASH_ADDR) ||
+ (aspeed_smc_has_dma(s) && addr == R_DMA_DRAM_ADDR) ||
+ (aspeed_smc_has_dma(s) && addr == R_DMA_LEN) ||
+ (aspeed_smc_has_dma(s) && addr == R_DMA_CHECKSUM) ||
(addr >= R_SEG_ADDR0 &&
addr < R_SEG_ADDR0 + s->ctrl->max_peripherals) ||
(addr >= s->r_ctrl0 && addr < s->r_ctrl0 + s->ctrl->max_peripherals)) {
@@ -1236,7 +1257,7 @@ static void aspeed_smc_dma_done(AspeedSMCState *s)
}
}
-static void aspeed_smc_dma_ctrl(AspeedSMCState *s, uint64_t dma_ctrl)
+static void aspeed_smc_dma_ctrl(AspeedSMCState *s, uint32_t dma_ctrl)
{
if (!(dma_ctrl & DMA_CTRL_ENABLE)) {
s->regs[R_DMA_CTRL] = dma_ctrl;
@@ -1261,6 +1282,46 @@ static void aspeed_smc_dma_ctrl(AspeedSMCState *s, uint64_t dma_ctrl)
aspeed_smc_dma_done(s);
}
+static inline bool aspeed_smc_dma_granted(AspeedSMCState *s)
+{
+ if (!(s->ctrl->features & ASPEED_SMC_FEATURE_DMA_GRANT)) {
+ return true;
+ }
+
+ if (!(s->regs[R_DMA_CTRL] & DMA_CTRL_GRANT)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: DMA not granted\n", __func__);
+ return false;
+ }
+
+ return true;
+}
+
+static void aspeed_2600_smc_dma_ctrl(AspeedSMCState *s, uint32_t dma_ctrl)
+{
+ /* Preserve DMA bits */
+ dma_ctrl |= s->regs[R_DMA_CTRL] & (DMA_CTRL_REQUEST | DMA_CTRL_GRANT);
+
+ if (dma_ctrl == 0xAEED0000) {
+ /* automatically grant request */
+ s->regs[R_DMA_CTRL] |= (DMA_CTRL_REQUEST | DMA_CTRL_GRANT);
+ return;
+ }
+
+ /* clear request */
+ if (dma_ctrl == 0xDEEA0000) {
+ s->regs[R_DMA_CTRL] &= ~(DMA_CTRL_REQUEST | DMA_CTRL_GRANT);
+ return;
+ }
+
+ if (!aspeed_smc_dma_granted(s)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: DMA not granted\n", __func__);
+ return;
+ }
+
+ aspeed_smc_dma_ctrl(s, dma_ctrl);
+ s->regs[R_DMA_CTRL] &= ~(DMA_CTRL_REQUEST | DMA_CTRL_GRANT);
+}
+
static void aspeed_smc_write(void *opaque, hwaddr addr, uint64_t data,
unsigned int size)
{
@@ -1292,13 +1353,16 @@ static void aspeed_smc_write(void *opaque, hwaddr addr, uint64_t data,
s->regs[addr] = value & 0xff;
} else if (addr == R_INTR_CTRL) {
s->regs[addr] = value;
- } else if (s->ctrl->has_dma && addr == R_DMA_CTRL) {
- aspeed_smc_dma_ctrl(s, value);
- } else if (s->ctrl->has_dma && addr == R_DMA_DRAM_ADDR) {
+ } else if (aspeed_smc_has_dma(s) && addr == R_DMA_CTRL) {
+ s->ctrl->dma_ctrl(s, value);
+ } else if (aspeed_smc_has_dma(s) && addr == R_DMA_DRAM_ADDR &&
+ aspeed_smc_dma_granted(s)) {
s->regs[addr] = DMA_DRAM_ADDR(s, value);
- } else if (s->ctrl->has_dma && addr == R_DMA_FLASH_ADDR) {
+ } else if (aspeed_smc_has_dma(s) && addr == R_DMA_FLASH_ADDR &&
+ aspeed_smc_dma_granted(s)) {
s->regs[addr] = DMA_FLASH_ADDR(s, value);
- } else if (s->ctrl->has_dma && addr == R_DMA_LEN) {
+ } else if (aspeed_smc_has_dma(s) && addr == R_DMA_LEN &&
+ aspeed_smc_dma_granted(s)) {
s->regs[addr] = DMA_LENGTH(value);
} else {
qemu_log_mask(LOG_UNIMP, "%s: not implemented: 0x%" HWADDR_PRIx "\n",
@@ -1386,7 +1450,9 @@ static void aspeed_smc_realize(DeviceState *dev, Error **errp)
memory_region_init_io(&s->mmio_flash, OBJECT(s),
&aspeed_smc_flash_default_ops, s, name,
s->ctrl->flash_window_size);
- sysbus_init_mmio(sbd, &s->mmio_flash);
+ memory_region_init_alias(&s->mmio_flash_alias, OBJECT(s), name,
+ &s->mmio_flash, 0, s->ctrl->flash_window_size);
+ sysbus_init_mmio(sbd, &s->mmio_flash_alias);
s->flashes = g_new0(AspeedSMCFlash, s->ctrl->max_peripherals);
@@ -1412,7 +1478,7 @@ static void aspeed_smc_realize(DeviceState *dev, Error **errp)
}
/* DMA support */
- if (s->ctrl->has_dma) {
+ if (aspeed_smc_has_dma(s)) {
aspeed_smc_dma_setup(s, errp);
}
}
@@ -1432,7 +1498,6 @@ static const VMStateDescription vmstate_aspeed_smc = {
static Property aspeed_smc_properties[] = {
DEFINE_PROP_UINT32("num-cs", AspeedSMCState, num_cs, 1),
DEFINE_PROP_BOOL("inject-failure", AspeedSMCState, inject_failure, false),
- DEFINE_PROP_UINT64("sdram-base", AspeedSMCState, sdram_base, 0),
DEFINE_PROP_LINK("dram", AspeedSMCState, dram_mr,
TYPE_MEMORY_REGION, MemoryRegion *),
DEFINE_PROP_END_OF_LIST(),