aspeed queue:

* Add AST2700 support
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEoPZlSPBIlev+awtgUaNDx8/77KEFAmZvtLUACgkQUaNDx8/7
 7KH8Ew/+K7OJYUsRhuLByLjaQ8kCsVdxMCFLtpCL9t6AgrMUXaI6WkkynPMKITQQ
 AHocO76TsWRMp962obnjvXgVRCrtvOI2W5jvgp1Gr554tW7YQClLiGhuf1FeORS9
 ZQhWryoC8vK8ymC7dAS5cyuiddWFUGC04P9lb9oXr88n6goZ1xRfKwM+RttgfCAm
 79SsK7g3TS8QOWH1kQwIQZyJKzwrw7bTM3Ijv9NmVKa050zWquMRZQeY18fgO6Ae
 p/pGpkf4Bc5iv+kIXoI4UN7Cx74aZoKInQ+DA71gtCWh/s09j9PkvOAfKWYAozD+
 VSaLvw4rvhRxgbs1SjoiMb5dDjJhngfzLhJX/P2FD1LCHRk+/uxk3fDDp2AqvQ6z
 IuWPb8FgWHqeiigcXkTW1JgUS85quIbjWBxreIrQiq+zR50EQy49elMRhzJlKsqZ
 3/ulk7xf+5M1+wS4bo7r8LPk5K8mFw9b4cxfnx0feZCjrl4ZfeWyDtaKzCAU0MJq
 KfpHo9R98imjVmcRWUouTaFow33OXheLdPFO8PofVnT38a4KIWlkin3zFMdTOAk+
 f8kWMPlXlRpKBYsjvP2aCpoY6CY8bHskdBH7xysM2W1FfKTw3dwZRpt4dgVPxqYj
 KZXiKxzwnC2gGi/wn+EdhZwYy1nNSZYGK8s+jxBXi2UBrwv4PpA=
 =TnR8
 -----END PGP SIGNATURE-----

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

aspeed queue:

* Add AST2700 support

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEEoPZlSPBIlev+awtgUaNDx8/77KEFAmZvtLUACgkQUaNDx8/7
# 7KH8Ew/+K7OJYUsRhuLByLjaQ8kCsVdxMCFLtpCL9t6AgrMUXaI6WkkynPMKITQQ
# AHocO76TsWRMp962obnjvXgVRCrtvOI2W5jvgp1Gr554tW7YQClLiGhuf1FeORS9
# ZQhWryoC8vK8ymC7dAS5cyuiddWFUGC04P9lb9oXr88n6goZ1xRfKwM+RttgfCAm
# 79SsK7g3TS8QOWH1kQwIQZyJKzwrw7bTM3Ijv9NmVKa050zWquMRZQeY18fgO6Ae
# p/pGpkf4Bc5iv+kIXoI4UN7Cx74aZoKInQ+DA71gtCWh/s09j9PkvOAfKWYAozD+
# VSaLvw4rvhRxgbs1SjoiMb5dDjJhngfzLhJX/P2FD1LCHRk+/uxk3fDDp2AqvQ6z
# IuWPb8FgWHqeiigcXkTW1JgUS85quIbjWBxreIrQiq+zR50EQy49elMRhzJlKsqZ
# 3/ulk7xf+5M1+wS4bo7r8LPk5K8mFw9b4cxfnx0feZCjrl4ZfeWyDtaKzCAU0MJq
# KfpHo9R98imjVmcRWUouTaFow33OXheLdPFO8PofVnT38a4KIWlkin3zFMdTOAk+
# f8kWMPlXlRpKBYsjvP2aCpoY6CY8bHskdBH7xysM2W1FfKTw3dwZRpt4dgVPxqYj
# KZXiKxzwnC2gGi/wn+EdhZwYy1nNSZYGK8s+jxBXi2UBrwv4PpA=
# =TnR8
# -----END PGP SIGNATURE-----
# gpg: Signature made Sun 16 Jun 2024 08:59:49 PM PDT
# gpg:                using RSA key A0F66548F04895EBFE6B0B6051A343C7CFFBECA1
# gpg: Good signature from "Cédric Le Goater <clg@kaod.org>" [undefined]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: A0F6 6548 F048 95EB FE6B  0B60 51A3 43C7 CFFB ECA1

* tag 'pull-aspeed-20240617' of https://github.com/legoater/qemu:
  MAINTAINERS: Add reviewers for ASPEED BMCs
  docs:aspeed: Add AST2700 Evaluation board
  test/avocado/machine_aspeed.py: Add AST2700 test case
  aspeed/soc: fix incorrect dram size for AST2700
  aspeed: Add an AST2700 eval board
  aspeed/soc: Add AST2700 support
  aspeed/intc: Add AST2700 support
  aspeed/scu: Add AST2700 support
  aspeed/smc: Add AST2700 support
  aspeed/smc: support different memory region ops for SMC flash region
  aspeed/smc: support 64 bits dma dram address
  aspeed/smc: support dma start length and 1 byte length unit
  aspeed/smc: correct device description
  aspeed/sdmc: Add AST2700 support
  aspeed/sdmc: fix coding style
  aspeed/sdmc: remove redundant macros
  aspeed/sli: Add AST2700 support
  aspeed/wdt: Add AST2700 support
  aspeed/smc: Reintroduce "dram-base" property for AST2700

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2024-06-17 09:20:05 -07:00
commit 79e6ec66ba
24 changed files with 2351 additions and 58 deletions

View File

@ -1158,6 +1158,9 @@ F: docs/system/arm/emcraft-sf2.rst
ASPEED BMCs
M: Cédric Le Goater <clg@kaod.org>
M: Peter Maydell <peter.maydell@linaro.org>
R: Steven Lee <steven_lee@aspeedtech.com>
R: Troy Lee <leetroy@gmail.com>
R: Jamin Lin <jamin_lin@aspeedtech.com>
R: Andrew Jeffery <andrew@codeconstruct.com.au>
R: Joel Stanley <joel@jms.id.au>
L: qemu-arm@nongnu.org

View File

@ -1,11 +1,12 @@
Aspeed family boards (``*-bmc``, ``ast2500-evb``, ``ast2600-evb``)
==================================================================
Aspeed family boards (``*-bmc``, ``ast2500-evb``, ``ast2600-evb``, ``ast2700-evb``)
===================================================================================
The QEMU Aspeed machines model BMCs of various OpenPOWER systems and
Aspeed evaluation boards. They are based on different releases of the
Aspeed SoC : the AST2400 integrating an ARM926EJ-S CPU (400MHz), the
AST2500 with an ARM1176JZS CPU (800MHz) and more recently the AST2600
with dual cores ARM Cortex-A7 CPUs (1.2GHz).
AST2500 with an ARM1176JZS CPU (800MHz), the AST2600
with dual cores ARM Cortex-A7 CPUs (1.2GHz) and more recently the AST2700
with quad cores ARM Cortex-A35 64 bits CPUs (1.6GHz)
The SoC comes with RAM, Gigabit ethernet, USB, SD/MMC, USB, SPI, I2C,
etc.
@ -38,6 +39,10 @@ AST2600 SoC based machines :
- ``qcom-dc-scm-v1-bmc`` Qualcomm DC-SCM V1 BMC
- ``qcom-firework-bmc`` Qualcomm Firework BMC
AST2700 SoC based machines :
- ``ast2700-evb`` Aspeed AST2700 Evaluation board (Cortex-A35)
Supported devices
-----------------
@ -66,6 +71,7 @@ Supported devices
* eMMC Boot Controller (dummy)
* PECI Controller (minimal)
* I3C Controller
* Internal Bridge Controller (SLI dummy)
Missing devices
@ -95,6 +101,10 @@ or directly from the OpenBMC GitHub release repository :
https://github.com/openbmc/openbmc/releases
or directly from the ASPEED Forked OpenBMC GitHub release repository :
https://github.com/AspeedTech-BMC/openbmc/releases
To boot a kernel directly from a Linux build tree:
.. code-block:: bash
@ -164,6 +174,27 @@ under Linux), use :
-M ast2500-evb,bmc-console=uart3
Boot the AST2700 machine from the flash image, use an MTD drive :
.. code-block:: bash
IMGDIR=ast2700-default
UBOOT_SIZE=$(stat --format=%s -L ${IMGDIR}/u-boot-nodtb.bin)
$ qemu-system-aarch64 -M ast2700-evb \
-device loader,force-raw=on,addr=0x400000000,file=${IMGDIR}/u-boot-nodtb.bin \
-device loader,force-raw=on,addr=$((0x400000000 + ${UBOOT_SIZE})),file=${IMGDIR}/u-boot.dtb \
-device loader,force-raw=on,addr=0x430000000,file=${IMGDIR}/bl31.bin \
-device loader,force-raw=on,addr=0x430080000,file=${IMGDIR}/optee/tee-raw.bin \
-device loader,cpu-num=0,addr=0x430000000 \
-device loader,cpu-num=1,addr=0x430000000 \
-device loader,cpu-num=2,addr=0x430000000 \
-device loader,cpu-num=3,addr=0x430000000 \
-smp 4 \
-drive file=${IMGDIR}/image-bmc,format=raw,if=mtd \
-nographic
Aspeed minibmc family boards (``ast1030-evb``)
==================================================================

View File

@ -178,6 +178,12 @@ struct AspeedMachineState {
#define AST2600_EVB_HW_STRAP1 0x000000C0
#define AST2600_EVB_HW_STRAP2 0x00000003
#ifdef TARGET_AARCH64
/* AST2700 evb hardware value */
#define AST2700_EVB_HW_STRAP1 0x000000C0
#define AST2700_EVB_HW_STRAP2 0x00000003
#endif
/* Tacoma hardware value */
#define TACOMA_BMC_HW_STRAP1 0x00000000
#define TACOMA_BMC_HW_STRAP2 0x00000040
@ -1588,6 +1594,26 @@ static void aspeed_minibmc_machine_ast1030_evb_class_init(ObjectClass *oc,
aspeed_machine_class_init_cpus_defaults(mc);
}
#ifdef TARGET_AARCH64
static void aspeed_machine_ast2700_evb_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
mc->desc = "Aspeed AST2700 EVB (Cortex-A35)";
amc->soc_name = "ast2700-a0";
amc->hw_strap1 = AST2700_EVB_HW_STRAP1;
amc->hw_strap2 = AST2700_EVB_HW_STRAP2;
amc->fmc_model = "w25q01jvq";
amc->spi_model = "w25q512jv";
amc->num_cs = 2;
amc->macs_mask = ASPEED_MAC0_ON | ASPEED_MAC1_ON | ASPEED_MAC2_ON;
amc->uart_default = ASPEED_DEV_UART12;
mc->default_ram_size = 1 * GiB;
aspeed_machine_class_init_cpus_defaults(mc);
}
#endif
static void aspeed_machine_qcom_dc_scm_v1_class_init(ObjectClass *oc,
void *data)
{
@ -1711,6 +1737,12 @@ static const TypeInfo aspeed_machine_types[] = {
.name = MACHINE_TYPE_NAME("ast1030-evb"),
.parent = TYPE_ASPEED_MACHINE,
.class_init = aspeed_minibmc_machine_ast1030_evb_class_init,
#ifdef TARGET_AARCH64
}, {
.name = MACHINE_TYPE_NAME("ast2700-evb"),
.parent = TYPE_ASPEED_MACHINE,
.class_init = aspeed_machine_ast2700_evb_class_init,
#endif
}, {
.name = TYPE_ASPEED_MACHINE,
.parent = TYPE_MACHINE,

648
hw/arm/aspeed_ast27x0.c Normal file
View File

@ -0,0 +1,648 @@
/*
* ASPEED SoC 27x0 family
*
* Copyright (C) 2024 ASPEED Technology Inc.
*
* This code is licensed under the GPL version 2 or later. See
* the COPYING file in the top-level directory.
*
* Implementation extracted from the AST2600 and adapted for AST27x0.
*/
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "hw/misc/unimp.h"
#include "hw/arm/aspeed_soc.h"
#include "qemu/module.h"
#include "qemu/error-report.h"
#include "hw/i2c/aspeed_i2c.h"
#include "net/net.h"
#include "sysemu/sysemu.h"
#include "hw/intc/arm_gicv3.h"
#include "qapi/qmp/qlist.h"
#include "qemu/log.h"
static const hwaddr aspeed_soc_ast2700_memmap[] = {
[ASPEED_DEV_SPI_BOOT] = 0x400000000,
[ASPEED_DEV_SRAM] = 0x10000000,
[ASPEED_DEV_SDMC] = 0x12C00000,
[ASPEED_DEV_SCU] = 0x12C02000,
[ASPEED_DEV_SCUIO] = 0x14C02000,
[ASPEED_DEV_UART0] = 0X14C33000,
[ASPEED_DEV_UART1] = 0X14C33100,
[ASPEED_DEV_UART2] = 0X14C33200,
[ASPEED_DEV_UART3] = 0X14C33300,
[ASPEED_DEV_UART4] = 0X12C1A000,
[ASPEED_DEV_UART5] = 0X14C33400,
[ASPEED_DEV_UART6] = 0X14C33500,
[ASPEED_DEV_UART7] = 0X14C33600,
[ASPEED_DEV_UART8] = 0X14C33700,
[ASPEED_DEV_UART9] = 0X14C33800,
[ASPEED_DEV_UART10] = 0X14C33900,
[ASPEED_DEV_UART11] = 0X14C33A00,
[ASPEED_DEV_UART12] = 0X14C33B00,
[ASPEED_DEV_WDT] = 0x14C37000,
[ASPEED_DEV_VUART] = 0X14C30000,
[ASPEED_DEV_FMC] = 0x14000000,
[ASPEED_DEV_SPI0] = 0x14010000,
[ASPEED_DEV_SPI1] = 0x14020000,
[ASPEED_DEV_SPI2] = 0x14030000,
[ASPEED_DEV_SDRAM] = 0x400000000,
[ASPEED_DEV_MII1] = 0x14040000,
[ASPEED_DEV_MII2] = 0x14040008,
[ASPEED_DEV_MII3] = 0x14040010,
[ASPEED_DEV_ETH1] = 0x14050000,
[ASPEED_DEV_ETH2] = 0x14060000,
[ASPEED_DEV_ETH3] = 0x14070000,
[ASPEED_DEV_EMMC] = 0x12090000,
[ASPEED_DEV_INTC] = 0x12100000,
[ASPEED_DEV_SLI] = 0x12C17000,
[ASPEED_DEV_SLIIO] = 0x14C1E000,
[ASPEED_GIC_DIST] = 0x12200000,
[ASPEED_GIC_REDIST] = 0x12280000,
};
#define AST2700_MAX_IRQ 288
/* Shared Peripheral Interrupt values below are offset by -32 from datasheet */
static const int aspeed_soc_ast2700_irqmap[] = {
[ASPEED_DEV_UART0] = 132,
[ASPEED_DEV_UART1] = 132,
[ASPEED_DEV_UART2] = 132,
[ASPEED_DEV_UART3] = 132,
[ASPEED_DEV_UART4] = 8,
[ASPEED_DEV_UART5] = 132,
[ASPEED_DEV_UART6] = 132,
[ASPEED_DEV_UART7] = 132,
[ASPEED_DEV_UART8] = 132,
[ASPEED_DEV_UART9] = 132,
[ASPEED_DEV_UART10] = 132,
[ASPEED_DEV_UART11] = 132,
[ASPEED_DEV_UART12] = 132,
[ASPEED_DEV_FMC] = 131,
[ASPEED_DEV_SDMC] = 0,
[ASPEED_DEV_SCU] = 12,
[ASPEED_DEV_ADC] = 130,
[ASPEED_DEV_XDMA] = 5,
[ASPEED_DEV_EMMC] = 15,
[ASPEED_DEV_GPIO] = 11,
[ASPEED_DEV_GPIO_1_8V] = 130,
[ASPEED_DEV_RTC] = 13,
[ASPEED_DEV_TIMER1] = 16,
[ASPEED_DEV_TIMER2] = 17,
[ASPEED_DEV_TIMER3] = 18,
[ASPEED_DEV_TIMER4] = 19,
[ASPEED_DEV_TIMER5] = 20,
[ASPEED_DEV_TIMER6] = 21,
[ASPEED_DEV_TIMER7] = 22,
[ASPEED_DEV_TIMER8] = 23,
[ASPEED_DEV_WDT] = 131,
[ASPEED_DEV_PWM] = 131,
[ASPEED_DEV_LPC] = 128,
[ASPEED_DEV_IBT] = 128,
[ASPEED_DEV_I2C] = 130,
[ASPEED_DEV_PECI] = 133,
[ASPEED_DEV_ETH1] = 132,
[ASPEED_DEV_ETH2] = 132,
[ASPEED_DEV_ETH3] = 132,
[ASPEED_DEV_HACE] = 4,
[ASPEED_DEV_KCS] = 128,
[ASPEED_DEV_DP] = 28,
[ASPEED_DEV_I3C] = 131,
};
/* GICINT 128 */
static const int aspeed_soc_ast2700_gic128_intcmap[] = {
[ASPEED_DEV_LPC] = 0,
[ASPEED_DEV_IBT] = 2,
[ASPEED_DEV_KCS] = 4,
};
/* GICINT 130 */
static const int aspeed_soc_ast2700_gic130_intcmap[] = {
[ASPEED_DEV_I2C] = 0,
[ASPEED_DEV_ADC] = 16,
[ASPEED_DEV_GPIO_1_8V] = 18,
};
/* GICINT 131 */
static const int aspeed_soc_ast2700_gic131_intcmap[] = {
[ASPEED_DEV_I3C] = 0,
[ASPEED_DEV_WDT] = 16,
[ASPEED_DEV_FMC] = 25,
[ASPEED_DEV_PWM] = 29,
};
/* GICINT 132 */
static const int aspeed_soc_ast2700_gic132_intcmap[] = {
[ASPEED_DEV_ETH1] = 0,
[ASPEED_DEV_ETH2] = 1,
[ASPEED_DEV_ETH3] = 2,
[ASPEED_DEV_UART0] = 7,
[ASPEED_DEV_UART1] = 8,
[ASPEED_DEV_UART2] = 9,
[ASPEED_DEV_UART3] = 10,
[ASPEED_DEV_UART5] = 11,
[ASPEED_DEV_UART6] = 12,
[ASPEED_DEV_UART7] = 13,
[ASPEED_DEV_UART8] = 14,
[ASPEED_DEV_UART9] = 15,
[ASPEED_DEV_UART10] = 16,
[ASPEED_DEV_UART11] = 17,
[ASPEED_DEV_UART12] = 18,
};
/* GICINT 133 */
static const int aspeed_soc_ast2700_gic133_intcmap[] = {
[ASPEED_DEV_PECI] = 4,
};
/* GICINT 128 ~ 136 */
struct gic_intc_irq_info {
int irq;
const int *ptr;
};
static const struct gic_intc_irq_info aspeed_soc_ast2700_gic_intcmap[] = {
{128, aspeed_soc_ast2700_gic128_intcmap},
{129, NULL},
{130, aspeed_soc_ast2700_gic130_intcmap},
{131, aspeed_soc_ast2700_gic131_intcmap},
{132, aspeed_soc_ast2700_gic132_intcmap},
{133, aspeed_soc_ast2700_gic133_intcmap},
{134, NULL},
{135, NULL},
{136, NULL},
};
static qemu_irq aspeed_soc_ast2700_get_irq(AspeedSoCState *s, int dev)
{
Aspeed27x0SoCState *a = ASPEED27X0_SOC(s);
AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
int i;
for (i = 0; i < ARRAY_SIZE(aspeed_soc_ast2700_gic_intcmap); i++) {
if (sc->irqmap[dev] == aspeed_soc_ast2700_gic_intcmap[i].irq) {
assert(aspeed_soc_ast2700_gic_intcmap[i].ptr);
return qdev_get_gpio_in(DEVICE(&a->intc.orgates[i]),
aspeed_soc_ast2700_gic_intcmap[i].ptr[dev]);
}
}
return qdev_get_gpio_in(DEVICE(&a->gic), sc->irqmap[dev]);
}
static uint64_t aspeed_ram_capacity_read(void *opaque, hwaddr addr,
unsigned int size)
{
qemu_log_mask(LOG_GUEST_ERROR,
"%s: DRAM read out of ram size, addr:0x%" PRIx64 "\n",
__func__, addr);
return 0;
}
static void aspeed_ram_capacity_write(void *opaque, hwaddr addr, uint64_t data,
unsigned int size)
{
AspeedSoCState *s = ASPEED_SOC(opaque);
ram_addr_t ram_size;
MemTxResult result;
ram_size = object_property_get_uint(OBJECT(&s->sdmc), "ram-size",
&error_abort);
/*
* Emulate ddr capacity hardware behavior.
* If writes the data to the address which is beyond the ram size,
* it would write the data to the "address % ram_size".
*/
result = address_space_write(&s->dram_as, addr % ram_size,
MEMTXATTRS_UNSPECIFIED, &data, 4);
if (result != MEMTX_OK) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: DRAM write failed, addr:0x%" HWADDR_PRIx
", data :0x%" PRIx64 "\n",
__func__, addr % ram_size, data);
}
}
static const MemoryRegionOps aspeed_ram_capacity_ops = {
.read = aspeed_ram_capacity_read,
.write = aspeed_ram_capacity_write,
.endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 1,
.max_access_size = 8,
},
};
/*
* SDMC should be realized first to get correct RAM size and max size
* values
*/
static bool aspeed_soc_ast2700_dram_init(DeviceState *dev, Error **errp)
{
ram_addr_t ram_size, max_ram_size;
Aspeed27x0SoCState *a = ASPEED27X0_SOC(dev);
AspeedSoCState *s = ASPEED_SOC(dev);
AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
ram_size = object_property_get_uint(OBJECT(&s->sdmc), "ram-size",
&error_abort);
max_ram_size = object_property_get_uint(OBJECT(&s->sdmc), "max-ram-size",
&error_abort);
memory_region_init(&s->dram_container, OBJECT(s), "ram-container",
ram_size);
memory_region_add_subregion(&s->dram_container, 0, s->dram_mr);
address_space_init(&s->dram_as, s->dram_mr, "dram");
/*
* Add a memory region beyond the RAM region to emulate
* ddr capacity hardware behavior.
*/
if (ram_size < max_ram_size) {
memory_region_init_io(&a->dram_empty, OBJECT(s),
&aspeed_ram_capacity_ops, s,
"ram-empty", max_ram_size - ram_size);
memory_region_add_subregion(s->memory,
sc->memmap[ASPEED_DEV_SDRAM] + ram_size,
&a->dram_empty);
}
memory_region_add_subregion(s->memory,
sc->memmap[ASPEED_DEV_SDRAM], &s->dram_container);
return true;
}
static void aspeed_soc_ast2700_init(Object *obj)
{
Aspeed27x0SoCState *a = ASPEED27X0_SOC(obj);
AspeedSoCState *s = ASPEED_SOC(obj);
AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
int i;
char socname[8];
char typename[64];
if (sscanf(sc->name, "%7s", socname) != 1) {
g_assert_not_reached();
}
for (i = 0; i < sc->num_cpus; i++) {
object_initialize_child(obj, "cpu[*]", &a->cpu[i],
aspeed_soc_cpu_type(sc));
}
object_initialize_child(obj, "gic", &a->gic, gicv3_class_name());
object_initialize_child(obj, "scu", &s->scu, TYPE_ASPEED_2700_SCU);
qdev_prop_set_uint32(DEVICE(&s->scu), "silicon-rev",
sc->silicon_rev);
object_property_add_alias(obj, "hw-strap1", OBJECT(&s->scu),
"hw-strap1");
object_property_add_alias(obj, "hw-strap2", OBJECT(&s->scu),
"hw-strap2");
object_property_add_alias(obj, "hw-prot-key", OBJECT(&s->scu),
"hw-prot-key");
object_initialize_child(obj, "scuio", &s->scuio, TYPE_ASPEED_2700_SCUIO);
qdev_prop_set_uint32(DEVICE(&s->scuio), "silicon-rev",
sc->silicon_rev);
snprintf(typename, sizeof(typename), "aspeed.fmc-%s", socname);
object_initialize_child(obj, "fmc", &s->fmc, typename);
for (i = 0; i < sc->spis_num; i++) {
snprintf(typename, sizeof(typename), "aspeed.spi%d-%s", i, socname);
object_initialize_child(obj, "spi[*]", &s->spi[i], typename);
}
snprintf(typename, sizeof(typename), "aspeed.sdmc-%s", socname);
object_initialize_child(obj, "sdmc", &s->sdmc, typename);
object_property_add_alias(obj, "ram-size", OBJECT(&s->sdmc),
"ram-size");
for (i = 0; i < sc->wdts_num; i++) {
snprintf(typename, sizeof(typename), "aspeed.wdt-%s", socname);
object_initialize_child(obj, "wdt[*]", &s->wdt[i], typename);
}
for (i = 0; i < sc->macs_num; i++) {
object_initialize_child(obj, "ftgmac100[*]", &s->ftgmac100[i],
TYPE_FTGMAC100);
object_initialize_child(obj, "mii[*]", &s->mii[i], TYPE_ASPEED_MII);
}
for (i = 0; i < sc->uarts_num; i++) {
object_initialize_child(obj, "uart[*]", &s->uart[i], TYPE_SERIAL_MM);
}
object_initialize_child(obj, "sli", &s->sli, TYPE_ASPEED_2700_SLI);
object_initialize_child(obj, "sliio", &s->sliio, TYPE_ASPEED_2700_SLIIO);
object_initialize_child(obj, "intc", &a->intc, TYPE_ASPEED_2700_INTC);
}
/*
* ASPEED ast2700 has 0x0 as cluster ID
*
* https://developer.arm.com/documentation/100236/0100/register-descriptions/aarch64-system-registers/multiprocessor-affinity-register--el1
*/
static uint64_t aspeed_calc_affinity(int cpu)
{
return (0x0 << ARM_AFF1_SHIFT) | cpu;
}
static bool aspeed_soc_ast2700_gic_realize(DeviceState *dev, Error **errp)
{
Aspeed27x0SoCState *a = ASPEED27X0_SOC(dev);
AspeedSoCState *s = ASPEED_SOC(dev);
AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
SysBusDevice *gicbusdev;
DeviceState *gicdev;
QList *redist_region_count;
int i;
gicbusdev = SYS_BUS_DEVICE(&a->gic);
gicdev = DEVICE(&a->gic);
qdev_prop_set_uint32(gicdev, "revision", 3);
qdev_prop_set_uint32(gicdev, "num-cpu", sc->num_cpus);
qdev_prop_set_uint32(gicdev, "num-irq", AST2700_MAX_IRQ);
redist_region_count = qlist_new();
qlist_append_int(redist_region_count, sc->num_cpus);
qdev_prop_set_array(gicdev, "redist-region-count", redist_region_count);
if (!sysbus_realize(gicbusdev, errp)) {
return false;
}
sysbus_mmio_map(gicbusdev, 0, sc->memmap[ASPEED_GIC_DIST]);
sysbus_mmio_map(gicbusdev, 1, sc->memmap[ASPEED_GIC_REDIST]);
for (i = 0; i < sc->num_cpus; i++) {
DeviceState *cpudev = DEVICE(&a->cpu[i]);
int NUM_IRQS = 256, ARCH_GIC_MAINT_IRQ = 9, VIRTUAL_PMU_IRQ = 7;
int ppibase = NUM_IRQS + i * GIC_INTERNAL + GIC_NR_SGIS;
const int timer_irq[] = {
[GTIMER_PHYS] = 14,
[GTIMER_VIRT] = 11,
[GTIMER_HYP] = 10,
[GTIMER_SEC] = 13,
};
int j;
for (j = 0; j < ARRAY_SIZE(timer_irq); j++) {
qdev_connect_gpio_out(cpudev, j,
qdev_get_gpio_in(gicdev, ppibase + timer_irq[j]));
}
qemu_irq irq = qdev_get_gpio_in(gicdev,
ppibase + ARCH_GIC_MAINT_IRQ);
qdev_connect_gpio_out_named(cpudev, "gicv3-maintenance-interrupt",
0, irq);
qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0,
qdev_get_gpio_in(gicdev, ppibase + VIRTUAL_PMU_IRQ));
sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
sysbus_connect_irq(gicbusdev, i + sc->num_cpus,
qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
sysbus_connect_irq(gicbusdev, i + 2 * sc->num_cpus,
qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ));
sysbus_connect_irq(gicbusdev, i + 3 * sc->num_cpus,
qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ));
}
return true;
}
static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp)
{
int i;
Aspeed27x0SoCState *a = ASPEED27X0_SOC(dev);
AspeedSoCState *s = ASPEED_SOC(dev);
AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
AspeedINTCClass *ic = ASPEED_INTC_GET_CLASS(&a->intc);
g_autofree char *sram_name = NULL;
/* Default boot region (SPI memory or ROMs) */
memory_region_init(&s->spi_boot_container, OBJECT(s),
"aspeed.spi_boot_container", 0x400000000);
memory_region_add_subregion(s->memory, sc->memmap[ASPEED_DEV_SPI_BOOT],
&s->spi_boot_container);
/* CPU */
for (i = 0; i < sc->num_cpus; i++) {
object_property_set_int(OBJECT(&a->cpu[i]), "mp-affinity",
aspeed_calc_affinity(i), &error_abort);
object_property_set_int(OBJECT(&a->cpu[i]), "cntfrq", 1125000000,
&error_abort);
object_property_set_link(OBJECT(&a->cpu[i]), "memory",
OBJECT(s->memory), &error_abort);
if (!qdev_realize(DEVICE(&a->cpu[i]), NULL, errp)) {
return;
}
}
/* GIC */
if (!aspeed_soc_ast2700_gic_realize(dev, errp)) {
return;
}
/* INTC */
if (!sysbus_realize(SYS_BUS_DEVICE(&a->intc), errp)) {
return;
}
aspeed_mmio_map(s, SYS_BUS_DEVICE(&a->intc), 0,
sc->memmap[ASPEED_DEV_INTC]);
/* GICINT orgates -> INTC -> GIC */
for (i = 0; i < ic->num_ints; i++) {
qdev_connect_gpio_out(DEVICE(&a->intc.orgates[i]), 0,
qdev_get_gpio_in(DEVICE(&a->intc), i));
sysbus_connect_irq(SYS_BUS_DEVICE(&a->intc), i,
qdev_get_gpio_in(DEVICE(&a->gic),
aspeed_soc_ast2700_gic_intcmap[i].irq));
}
/* SRAM */
sram_name = g_strdup_printf("aspeed.sram.%d", CPU(&a->cpu[0])->cpu_index);
if (!memory_region_init_ram(&s->sram, OBJECT(s), sram_name, sc->sram_size,
errp)) {
return;
}
memory_region_add_subregion(s->memory,
sc->memmap[ASPEED_DEV_SRAM], &s->sram);
/* SCU */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->scu), errp)) {
return;
}
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->scu), 0, sc->memmap[ASPEED_DEV_SCU]);
/* SCU1 */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->scuio), errp)) {
return;
}
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->scuio), 0,
sc->memmap[ASPEED_DEV_SCUIO]);
/* UART */
if (!aspeed_soc_uart_realize(s, errp)) {
return;
}
/* FMC, The number of CS is set at the board level */
object_property_set_int(OBJECT(&s->fmc), "dram-base",
sc->memmap[ASPEED_DEV_SDRAM],
&error_abort);
object_property_set_link(OBJECT(&s->fmc), "dram", OBJECT(s->dram_mr),
&error_abort);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->fmc), errp)) {
return;
}
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->fmc), 0, sc->memmap[ASPEED_DEV_FMC]);
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->fmc), 1,
ASPEED_SMC_GET_CLASS(&s->fmc)->flash_window_base);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->fmc), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_FMC));
/* Set up an alias on the FMC CE0 region (boot default) */
MemoryRegion *fmc0_mmio = &s->fmc.flashes[0].mmio;
memory_region_init_alias(&s->spi_boot, OBJECT(s), "aspeed.spi_boot",
fmc0_mmio, 0, memory_region_size(fmc0_mmio));
memory_region_add_subregion(&s->spi_boot_container, 0x0, &s->spi_boot);
/* SPI */
for (i = 0; i < sc->spis_num; i++) {
object_property_set_link(OBJECT(&s->spi[i]), "dram",
OBJECT(s->dram_mr), &error_abort);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), errp)) {
return;
}
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->spi[i]), 0,
sc->memmap[ASPEED_DEV_SPI0 + i]);
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->spi[i]), 1,
ASPEED_SMC_GET_CLASS(&s->spi[i])->flash_window_base);
}
/*
* SDMC - SDRAM Memory Controller
* The SDMC controller is unlocked at SPL stage.
* At present, only supports to emulate booting
* start from u-boot stage. Set SDMC controller
* unlocked by default. It is a temporarily solution.
*/
object_property_set_bool(OBJECT(&s->sdmc), "unlocked", true,
&error_abort);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->sdmc), errp)) {
return;
}
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sdmc), 0,
sc->memmap[ASPEED_DEV_SDMC]);
/* RAM */
if (!aspeed_soc_ast2700_dram_init(dev, errp)) {
return;
}
for (i = 0; i < sc->macs_num; i++) {
object_property_set_bool(OBJECT(&s->ftgmac100[i]), "aspeed", true,
&error_abort);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->ftgmac100[i]), errp)) {
return;
}
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->ftgmac100[i]), 0,
sc->memmap[ASPEED_DEV_ETH1 + i]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->ftgmac100[i]), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_ETH1 + i));
object_property_set_link(OBJECT(&s->mii[i]), "nic",
OBJECT(&s->ftgmac100[i]), &error_abort);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->mii[i]), errp)) {
return;
}
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->mii[i]), 0,
sc->memmap[ASPEED_DEV_MII1 + i]);
}
/* Watch dog */
for (i = 0; i < sc->wdts_num; i++) {
AspeedWDTClass *awc = ASPEED_WDT_GET_CLASS(&s->wdt[i]);
hwaddr wdt_offset = sc->memmap[ASPEED_DEV_WDT] + i * awc->iosize;
object_property_set_link(OBJECT(&s->wdt[i]), "scu", OBJECT(&s->scu),
&error_abort);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), errp)) {
return;
}
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->wdt[i]), 0, wdt_offset);
}
/* SLI */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->sli), errp)) {
return;
}
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sli), 0, sc->memmap[ASPEED_DEV_SLI]);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->sliio), errp)) {
return;
}
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sliio), 0,
sc->memmap[ASPEED_DEV_SLIIO]);
create_unimplemented_device("ast2700.dpmcu", 0x11000000, 0x40000);
create_unimplemented_device("ast2700.iomem0", 0x12000000, 0x01000000);
create_unimplemented_device("ast2700.iomem1", 0x14000000, 0x01000000);
create_unimplemented_device("ast2700.ltpi", 0x30000000, 0x1000000);
create_unimplemented_device("ast2700.io", 0x0, 0x4000000);
}
static void aspeed_soc_ast2700_class_init(ObjectClass *oc, void *data)
{
static const char * const valid_cpu_types[] = {
ARM_CPU_TYPE_NAME("cortex-a35"),
NULL
};
DeviceClass *dc = DEVICE_CLASS(oc);
AspeedSoCClass *sc = ASPEED_SOC_CLASS(oc);
/* Reason: The Aspeed SoC can only be instantiated from a board */
dc->user_creatable = false;
dc->realize = aspeed_soc_ast2700_realize;
sc->name = "ast2700-a0";
sc->valid_cpu_types = valid_cpu_types;
sc->silicon_rev = AST2700_A0_SILICON_REV;
sc->sram_size = 0x20000;
sc->spis_num = 3;
sc->wdts_num = 8;
sc->macs_num = 1;
sc->uarts_num = 13;
sc->num_cpus = 4;
sc->uarts_base = ASPEED_DEV_UART0;
sc->irqmap = aspeed_soc_ast2700_irqmap;
sc->memmap = aspeed_soc_ast2700_memmap;
sc->get_irq = aspeed_soc_ast2700_get_irq;
}
static const TypeInfo aspeed_soc_ast27x0_types[] = {
{
.name = TYPE_ASPEED27X0_SOC,
.parent = TYPE_ASPEED_SOC,
.instance_size = sizeof(Aspeed27x0SoCState),
.abstract = true,
}, {
.name = "ast2700-a0",
.parent = TYPE_ASPEED27X0_SOC,
.instance_init = aspeed_soc_ast2700_init,
.class_init = aspeed_soc_ast2700_class_init,
},
};
DEFINE_TYPES(aspeed_soc_ast27x0_types)

View File

@ -49,6 +49,7 @@ arm_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files(
'aspeed_ast10x0.c',
'aspeed_eeprom.c',
'fby35.c'))
arm_ss.add(when: ['CONFIG_ASPEED_SOC', 'TARGET_AARCH64'], if_true: files('aspeed_ast27x0.c'))
arm_ss.add(when: 'CONFIG_MPS2', if_true: files('mps2.c'))
arm_ss.add(when: 'CONFIG_MPS2', if_true: files('mps2-tz.c'))
arm_ss.add(when: 'CONFIG_MSF2', if_true: files('msf2-soc.c'))

361
hw/intc/aspeed_intc.c Normal file
View File

@ -0,0 +1,361 @@
/*
* ASPEED INTC Controller
*
* Copyright (C) 2024 ASPEED Technology Inc.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "hw/intc/aspeed_intc.h"
#include "hw/irq.h"
#include "qemu/log.h"
#include "trace.h"
#include "hw/registerfields.h"
#include "qapi/error.h"
/* INTC Registers */
REG32(GICINT128_EN, 0x1000)
REG32(GICINT128_STATUS, 0x1004)
REG32(GICINT129_EN, 0x1100)
REG32(GICINT129_STATUS, 0x1104)
REG32(GICINT130_EN, 0x1200)
REG32(GICINT130_STATUS, 0x1204)
REG32(GICINT131_EN, 0x1300)
REG32(GICINT131_STATUS, 0x1304)
REG32(GICINT132_EN, 0x1400)
REG32(GICINT132_STATUS, 0x1404)
REG32(GICINT133_EN, 0x1500)
REG32(GICINT133_STATUS, 0x1504)
REG32(GICINT134_EN, 0x1600)
REG32(GICINT134_STATUS, 0x1604)
REG32(GICINT135_EN, 0x1700)
REG32(GICINT135_STATUS, 0x1704)
REG32(GICINT136_EN, 0x1800)
REG32(GICINT136_STATUS, 0x1804)
#define GICINT_STATUS_BASE R_GICINT128_STATUS
static void aspeed_intc_update(AspeedINTCState *s, int irq, int level)
{
AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
if (irq >= aic->num_ints) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid interrupt number: %d\n",
__func__, irq);
return;
}
trace_aspeed_intc_update_irq(irq, level);
qemu_set_irq(s->output_pins[irq], level);
}
/*
* The address of GICINT128 to GICINT136 are from 0x1000 to 0x1804.
* Utilize "address & 0x0f00" to get the irq and irq output pin index
* The value of irq should be 0 to num_ints.
* The irq 0 indicates GICINT128, irq 1 indicates GICINT129 and so on.
*/
static void aspeed_intc_set_irq(void *opaque, int irq, int level)
{
AspeedINTCState *s = (AspeedINTCState *)opaque;
AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
uint32_t status_addr = GICINT_STATUS_BASE + ((0x100 * irq) >> 2);
uint32_t select = 0;
uint32_t enable;
int i;
if (irq >= aic->num_ints) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid interrupt number: %d\n",
__func__, irq);
return;
}
trace_aspeed_intc_set_irq(irq, level);
enable = s->enable[irq];
if (!level) {
return;
}
for (i = 0; i < aic->num_lines; i++) {
if (s->orgates[irq].levels[i]) {
if (enable & BIT(i)) {
select |= BIT(i);
}
}
}
if (!select) {
return;
}
trace_aspeed_intc_select(select);
if (s->mask[irq] || s->regs[status_addr]) {
/*
* a. mask is not 0 means in ISR mode
* sources interrupt routine are executing.
* b. status register value is not 0 means previous
* source interrupt does not be executed, yet.
*
* save source interrupt to pending variable.
*/
s->pending[irq] |= select;
trace_aspeed_intc_pending_irq(irq, s->pending[irq]);
} else {
/*
* notify firmware which source interrupt are coming
* by setting status register
*/
s->regs[status_addr] = select;
trace_aspeed_intc_trigger_irq(irq, s->regs[status_addr]);
aspeed_intc_update(s, irq, 1);
}
}
static uint64_t aspeed_intc_read(void *opaque, hwaddr offset, unsigned int size)
{
AspeedINTCState *s = ASPEED_INTC(opaque);
uint32_t addr = offset >> 2;
uint32_t value = 0;
if (addr >= ASPEED_INTC_NR_REGS) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
__func__, offset);
return 0;
}
value = s->regs[addr];
trace_aspeed_intc_read(offset, size, value);
return value;
}
static void aspeed_intc_write(void *opaque, hwaddr offset, uint64_t data,
unsigned size)
{
AspeedINTCState *s = ASPEED_INTC(opaque);
AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
uint32_t addr = offset >> 2;
uint32_t old_enable;
uint32_t change;
uint32_t irq;
if (addr >= ASPEED_INTC_NR_REGS) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
__func__, offset);
return;
}
trace_aspeed_intc_write(offset, size, data);
switch (addr) {
case R_GICINT128_EN:
case R_GICINT129_EN:
case R_GICINT130_EN:
case R_GICINT131_EN:
case R_GICINT132_EN:
case R_GICINT133_EN:
case R_GICINT134_EN:
case R_GICINT135_EN:
case R_GICINT136_EN:
irq = (offset & 0x0f00) >> 8;
if (irq >= aic->num_ints) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid interrupt number: %d\n",
__func__, irq);
return;
}
/*
* These registers are used for enable sources interrupt and
* mask and unmask source interrupt while executing source ISR.
*/
/* disable all source interrupt */
if (!data && !s->enable[irq]) {
s->regs[addr] = data;
return;
}
old_enable = s->enable[irq];
s->enable[irq] |= data;
/* enable new source interrupt */
if (old_enable != s->enable[irq]) {
trace_aspeed_intc_enable(s->enable[irq]);
s->regs[addr] = data;
return;
}
/* mask and unmask source interrupt */
change = s->regs[addr] ^ data;
if (change & data) {
s->mask[irq] &= ~change;
trace_aspeed_intc_unmask(change, s->mask[irq]);
} else {
s->mask[irq] |= change;
trace_aspeed_intc_mask(change, s->mask[irq]);
}
s->regs[addr] = data;
break;
case R_GICINT128_STATUS:
case R_GICINT129_STATUS:
case R_GICINT130_STATUS:
case R_GICINT131_STATUS:
case R_GICINT132_STATUS:
case R_GICINT133_STATUS:
case R_GICINT134_STATUS:
case R_GICINT135_STATUS:
case R_GICINT136_STATUS:
irq = (offset & 0x0f00) >> 8;
if (irq >= aic->num_ints) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid interrupt number: %d\n",
__func__, irq);
return;
}
/* clear status */
s->regs[addr] &= ~data;
/*
* These status registers are used for notify sources ISR are executed.
* If one source ISR is executed, it will clear one bit.
* If it clear all bits, it means to initialize this register status
* rather than sources ISR are executed.
*/
if (data == 0xffffffff) {
return;
}
/* All source ISR execution are done */
if (!s->regs[addr]) {
trace_aspeed_intc_all_isr_done(irq);
if (s->pending[irq]) {
/*
* handle pending source interrupt
* notify firmware which source interrupt are pending
* by setting status register
*/
s->regs[addr] = s->pending[irq];
s->pending[irq] = 0;
trace_aspeed_intc_trigger_irq(irq, s->regs[addr]);
aspeed_intc_update(s, irq, 1);
} else {
/* clear irq */
trace_aspeed_intc_clear_irq(irq, 0);
aspeed_intc_update(s, irq, 0);
}
}
break;
default:
s->regs[addr] = data;
break;
}
return;
}
static const MemoryRegionOps aspeed_intc_ops = {
.read = aspeed_intc_read,
.write = aspeed_intc_write,
.endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 4,
.max_access_size = 4,
}
};
static void aspeed_intc_instance_init(Object *obj)
{
AspeedINTCState *s = ASPEED_INTC(obj);
AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
int i;
assert(aic->num_ints <= ASPEED_INTC_NR_INTS);
for (i = 0; i < aic->num_ints; i++) {
object_initialize_child(obj, "intc-orgates[*]", &s->orgates[i],
TYPE_OR_IRQ);
object_property_set_int(OBJECT(&s->orgates[i]), "num-lines",
aic->num_lines, &error_abort);
}
}
static void aspeed_intc_reset(DeviceState *dev)
{
AspeedINTCState *s = ASPEED_INTC(dev);
memset(s->regs, 0, sizeof(s->regs));
memset(s->enable, 0, sizeof(s->enable));
memset(s->mask, 0, sizeof(s->mask));
memset(s->pending, 0, sizeof(s->pending));
}
static void aspeed_intc_realize(DeviceState *dev, Error **errp)
{
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
AspeedINTCState *s = ASPEED_INTC(dev);
AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
int i;
memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_intc_ops, s,
TYPE_ASPEED_INTC ".regs", ASPEED_INTC_NR_REGS << 2);
sysbus_init_mmio(sbd, &s->iomem);
qdev_init_gpio_in(dev, aspeed_intc_set_irq, aic->num_ints);
for (i = 0; i < aic->num_ints; i++) {
if (!qdev_realize(DEVICE(&s->orgates[i]), NULL, errp)) {
return;
}
sysbus_init_irq(sbd, &s->output_pins[i]);
}
}
static void aspeed_intc_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->desc = "ASPEED INTC Controller";
dc->realize = aspeed_intc_realize;
dc->reset = aspeed_intc_reset;
dc->vmsd = NULL;
}
static const TypeInfo aspeed_intc_info = {
.name = TYPE_ASPEED_INTC,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_init = aspeed_intc_instance_init,
.instance_size = sizeof(AspeedINTCState),
.class_init = aspeed_intc_class_init,
.class_size = sizeof(AspeedINTCClass),
.abstract = true,
};
static void aspeed_2700_intc_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass);
dc->desc = "ASPEED 2700 INTC Controller";
aic->num_lines = 32;
aic->num_ints = 9;
}
static const TypeInfo aspeed_2700_intc_info = {
.name = TYPE_ASPEED_2700_INTC,
.parent = TYPE_ASPEED_INTC,
.class_init = aspeed_2700_intc_class_init,
};
static void aspeed_intc_register_types(void)
{
type_register_static(&aspeed_intc_info);
type_register_static(&aspeed_2700_intc_info);
}
type_init(aspeed_intc_register_types);

View File

@ -14,6 +14,7 @@ system_ss.add(when: 'CONFIG_ARM_GICV3_TCG', if_true: files(
))
system_ss.add(when: 'CONFIG_ALLWINNER_A10_PIC', if_true: files('allwinner-a10-pic.c'))
system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_vic.c'))
system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_intc.c'))
system_ss.add(when: 'CONFIG_ETRAXFS', if_true: files('etraxfs_pic.c'))
system_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_gic.c', 'exynos4210_combiner.c'))
system_ss.add(when: 'CONFIG_GOLDFISH_PIC', if_true: files('goldfish_pic.c'))

View File

@ -79,6 +79,19 @@ aspeed_vic_update_fiq(int flags) "Raising FIQ: %d"
aspeed_vic_update_irq(int flags) "Raising IRQ: %d"
aspeed_vic_read(uint64_t offset, unsigned size, uint32_t value) "From 0x%" PRIx64 " of size %u: 0x%" PRIx32
aspeed_vic_write(uint64_t offset, unsigned size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
# aspeed_intc.c
aspeed_intc_read(uint64_t offset, unsigned size, uint32_t value) "From 0x%" PRIx64 " of size %u: 0x%" PRIx32
aspeed_intc_write(uint64_t offset, unsigned size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
aspeed_intc_set_irq(int irq, int level) "Set IRQ %d: %d"
aspeed_intc_clear_irq(int irq, int level) "Clear IRQ %d: %d"
aspeed_intc_update_irq(int irq, int level) "Update IRQ: %d: %d"
aspeed_intc_pending_irq(int irq, uint32_t value) "Pending IRQ: %d: 0x%x"
aspeed_intc_trigger_irq(int irq, uint32_t value) "Trigger IRQ: %d: 0x%x"
aspeed_intc_all_isr_done(int irq) "All source ISR execution are done: %d"
aspeed_intc_enable(uint32_t value) "Enable: 0x%x"
aspeed_intc_select(uint32_t value) "Select: 0x%x"
aspeed_intc_mask(uint32_t change, uint32_t value) "Mask: 0x%x: 0x%x"
aspeed_intc_unmask(uint32_t change, uint32_t value) "UnMask: 0x%x: 0x%x"
# arm_gic.c
gic_enable_irq(int irq) "irq %d enabled"

View File

@ -134,6 +134,48 @@
#define AST2600_CLK TO_REG(0x40)
#define AST2700_SILICON_REV TO_REG(0x00)
#define AST2700_HW_STRAP1 TO_REG(0x10)
#define AST2700_HW_STRAP1_CLR TO_REG(0x14)
#define AST2700_HW_STRAP1_LOCK TO_REG(0x20)
#define AST2700_HW_STRAP1_SEC1 TO_REG(0x24)
#define AST2700_HW_STRAP1_SEC2 TO_REG(0x28)
#define AST2700_HW_STRAP1_SEC3 TO_REG(0x2C)
#define AST2700_SCU_CLK_SEL_1 TO_REG(0x280)
#define AST2700_SCU_HPLL_PARAM TO_REG(0x300)
#define AST2700_SCU_HPLL_EXT_PARAM TO_REG(0x304)
#define AST2700_SCU_DPLL_PARAM TO_REG(0x308)
#define AST2700_SCU_DPLL_EXT_PARAM TO_REG(0x30c)
#define AST2700_SCU_MPLL_PARAM TO_REG(0x310)
#define AST2700_SCU_MPLL_EXT_PARAM TO_REG(0x314)
#define AST2700_SCU_D1CLK_PARAM TO_REG(0x320)
#define AST2700_SCU_D2CLK_PARAM TO_REG(0x330)
#define AST2700_SCU_CRT1CLK_PARAM TO_REG(0x340)
#define AST2700_SCU_CRT2CLK_PARAM TO_REG(0x350)
#define AST2700_SCU_MPHYCLK_PARAM TO_REG(0x360)
#define AST2700_SCU_FREQ_CNTR TO_REG(0x3b0)
#define AST2700_SCU_CPU_SCRATCH_0 TO_REG(0x780)
#define AST2700_SCU_CPU_SCRATCH_1 TO_REG(0x784)
#define AST2700_SCUIO_CLK_STOP_CTL_1 TO_REG(0x240)
#define AST2700_SCUIO_CLK_STOP_CLR_1 TO_REG(0x244)
#define AST2700_SCUIO_CLK_STOP_CTL_2 TO_REG(0x260)
#define AST2700_SCUIO_CLK_STOP_CLR_2 TO_REG(0x264)
#define AST2700_SCUIO_CLK_SEL_1 TO_REG(0x280)
#define AST2700_SCUIO_CLK_SEL_2 TO_REG(0x284)
#define AST2700_SCUIO_HPLL_PARAM TO_REG(0x300)
#define AST2700_SCUIO_HPLL_EXT_PARAM TO_REG(0x304)
#define AST2700_SCUIO_APLL_PARAM TO_REG(0x310)
#define AST2700_SCUIO_APLL_EXT_PARAM TO_REG(0x314)
#define AST2700_SCUIO_DPLL_PARAM TO_REG(0x320)
#define AST2700_SCUIO_DPLL_EXT_PARAM TO_REG(0x324)
#define AST2700_SCUIO_DPLL_PARAM_READ TO_REG(0x328)
#define AST2700_SCUIO_DPLL_EXT_PARAM_READ TO_REG(0x32c)
#define AST2700_SCUIO_UARTCLK_GEN TO_REG(0x330)
#define AST2700_SCUIO_HUARTCLK_GEN TO_REG(0x334)
#define AST2700_SCUIO_CLK_DUTY_MEAS_RST TO_REG(0x388)
#define SCU_IO_REGION_SIZE 0x1000
static const uint32_t ast2400_a0_resets[ASPEED_SCU_NR_REGS] = {
@ -244,6 +286,25 @@ static uint32_t aspeed_1030_scu_get_apb_freq(AspeedSCUState *s)
/ asc->apb_divider;
}
static uint32_t aspeed_2700_scu_get_apb_freq(AspeedSCUState *s)
{
AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(s);
uint32_t hpll = asc->calc_hpll(s, s->regs[AST2700_SCU_HPLL_PARAM]);
return hpll / (SCU_CLK_GET_PCLK_DIV(s->regs[AST2700_SCU_CLK_SEL_1]) + 1)
/ asc->apb_divider;
}
static uint32_t aspeed_2700_scuio_get_apb_freq(AspeedSCUState *s)
{
AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(s);
uint32_t hpll = asc->calc_hpll(s, s->regs[AST2700_SCUIO_HPLL_PARAM]);
return hpll /
(SCUIO_AST2700_CLK_GET_PCLK_DIV(s->regs[AST2700_SCUIO_CLK_SEL_1]) + 1)
/ asc->apb_divider;
}
static uint64_t aspeed_scu_read(void *opaque, hwaddr offset, unsigned size)
{
AspeedSCUState *s = ASPEED_SCU(opaque);
@ -258,7 +319,8 @@ static uint64_t aspeed_scu_read(void *opaque, hwaddr offset, unsigned size)
switch (reg) {
case RNG_DATA:
/* On hardware, RNG_DATA works regardless of
/*
* On hardware, RNG_DATA works regardless of
* the state of the enable bit in RNG_CTRL
*/
s->regs[RNG_DATA] = aspeed_scu_get_random();
@ -494,6 +556,9 @@ static uint32_t aspeed_silicon_revs[] = {
AST2600_A3_SILICON_REV,
AST1030_A0_SILICON_REV,
AST1030_A1_SILICON_REV,
AST2700_A0_SILICON_REV,
AST2720_A0_SILICON_REV,
AST2750_A0_SILICON_REV,
};
bool is_supported_silicon_rev(uint32_t silicon_rev)
@ -783,6 +848,243 @@ static const TypeInfo aspeed_2600_scu_info = {
.class_init = aspeed_2600_scu_class_init,
};
static uint64_t aspeed_ast2700_scu_read(void *opaque, hwaddr offset,
unsigned size)
{
AspeedSCUState *s = ASPEED_SCU(opaque);
int reg = TO_REG(offset);
if (reg >= ASPEED_AST2700_SCU_NR_REGS) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
__func__, offset);
return 0;
}
switch (reg) {
default:
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Unhandled read at offset 0x%" HWADDR_PRIx "\n",
__func__, offset);
}
trace_aspeed_ast2700_scu_read(offset, size, s->regs[reg]);
return s->regs[reg];
}
static void aspeed_ast2700_scu_write(void *opaque, hwaddr offset,
uint64_t data64, unsigned size)
{
AspeedSCUState *s = ASPEED_SCU(opaque);
int reg = TO_REG(offset);
/* Truncate here so bitwise operations below behave as expected */
uint32_t data = data64;
if (reg >= ASPEED_AST2700_SCU_NR_REGS) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
__func__, offset);
return;
}
trace_aspeed_ast2700_scu_write(offset, size, data);
switch (reg) {
default:
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Unhandled write at offset 0x%" HWADDR_PRIx "\n",
__func__, offset);
break;
}
s->regs[reg] = data;
}
static const MemoryRegionOps aspeed_ast2700_scu_ops = {
.read = aspeed_ast2700_scu_read,
.write = aspeed_ast2700_scu_write,
.endianness = DEVICE_LITTLE_ENDIAN,
.valid.min_access_size = 1,
.valid.max_access_size = 8,
.valid.unaligned = false,
};
static const uint32_t ast2700_a0_resets[ASPEED_AST2700_SCU_NR_REGS] = {
[AST2700_SILICON_REV] = AST2700_A0_SILICON_REV,
[AST2700_HW_STRAP1] = 0x00000800,
[AST2700_HW_STRAP1_CLR] = 0xFFF0FFF0,
[AST2700_HW_STRAP1_LOCK] = 0x00000FFF,
[AST2700_HW_STRAP1_SEC1] = 0x000000FF,
[AST2700_HW_STRAP1_SEC2] = 0x00000000,
[AST2700_HW_STRAP1_SEC3] = 0x1000408F,
[AST2700_SCU_HPLL_PARAM] = 0x0000009f,
[AST2700_SCU_HPLL_EXT_PARAM] = 0x8000004f,
[AST2700_SCU_DPLL_PARAM] = 0x0080009f,
[AST2700_SCU_DPLL_EXT_PARAM] = 0x8000004f,
[AST2700_SCU_MPLL_PARAM] = 0x00000040,
[AST2700_SCU_MPLL_EXT_PARAM] = 0x80000000,
[AST2700_SCU_D1CLK_PARAM] = 0x00050002,
[AST2700_SCU_D2CLK_PARAM] = 0x00050002,
[AST2700_SCU_CRT1CLK_PARAM] = 0x00050002,
[AST2700_SCU_CRT2CLK_PARAM] = 0x00050002,
[AST2700_SCU_MPHYCLK_PARAM] = 0x0000004c,
[AST2700_SCU_FREQ_CNTR] = 0x000375eb,
[AST2700_SCU_CPU_SCRATCH_0] = 0x00000000,
[AST2700_SCU_CPU_SCRATCH_1] = 0x00000004,
};
static void aspeed_ast2700_scu_reset(DeviceState *dev)
{
AspeedSCUState *s = ASPEED_SCU(dev);
AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(dev);
memcpy(s->regs, asc->resets, asc->nr_regs * 4);
}
static void aspeed_2700_scu_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass);
dc->desc = "ASPEED 2700 System Control Unit";
dc->reset = aspeed_ast2700_scu_reset;
asc->resets = ast2700_a0_resets;
asc->calc_hpll = aspeed_2600_scu_calc_hpll;
asc->get_apb = aspeed_2700_scu_get_apb_freq;
asc->apb_divider = 4;
asc->nr_regs = ASPEED_AST2700_SCU_NR_REGS;
asc->clkin_25Mhz = true;
asc->ops = &aspeed_ast2700_scu_ops;
}
static uint64_t aspeed_ast2700_scuio_read(void *opaque, hwaddr offset,
unsigned size)
{
AspeedSCUState *s = ASPEED_SCU(opaque);
int reg = TO_REG(offset);
if (reg >= ASPEED_AST2700_SCU_NR_REGS) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
__func__, offset);
return 0;
}
switch (reg) {
default:
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Unhandled read at offset 0x%" HWADDR_PRIx "\n",
__func__, offset);
}
trace_aspeed_ast2700_scuio_read(offset, size, s->regs[reg]);
return s->regs[reg];
}
static void aspeed_ast2700_scuio_write(void *opaque, hwaddr offset,
uint64_t data64, unsigned size)
{
AspeedSCUState *s = ASPEED_SCU(opaque);
int reg = TO_REG(offset);
/* Truncate here so bitwise operations below behave as expected */
uint32_t data = data64;
bool updated = false;
if (reg >= ASPEED_AST2700_SCU_NR_REGS) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
__func__, offset);
return;
}
trace_aspeed_ast2700_scuio_write(offset, size, data);
switch (reg) {
case AST2700_SCUIO_CLK_STOP_CTL_1:
case AST2700_SCUIO_CLK_STOP_CTL_2:
s->regs[reg] |= data;
updated = true;
break;
case AST2700_SCUIO_CLK_STOP_CLR_1:
case AST2700_SCUIO_CLK_STOP_CLR_2:
s->regs[reg - 1] ^= data;
updated = true;
break;
default:
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Unhandled write at offset 0x%" HWADDR_PRIx "\n",
__func__, offset);
break;
}
if (!updated) {
s->regs[reg] = data;
}
}
static const MemoryRegionOps aspeed_ast2700_scuio_ops = {
.read = aspeed_ast2700_scuio_read,
.write = aspeed_ast2700_scuio_write,
.endianness = DEVICE_LITTLE_ENDIAN,
.valid.min_access_size = 1,
.valid.max_access_size = 8,
.valid.unaligned = false,
};
static const uint32_t ast2700_a0_resets_io[ASPEED_AST2700_SCU_NR_REGS] = {
[AST2700_SILICON_REV] = 0x06000003,
[AST2700_HW_STRAP1] = 0x00000504,
[AST2700_HW_STRAP1_CLR] = 0xFFF0FFF0,
[AST2700_HW_STRAP1_LOCK] = 0x00000FFF,
[AST2700_HW_STRAP1_SEC1] = 0x000000FF,
[AST2700_HW_STRAP1_SEC2] = 0x00000000,
[AST2700_HW_STRAP1_SEC3] = 0x1000408F,
[AST2700_SCUIO_CLK_STOP_CTL_1] = 0xffff8400,
[AST2700_SCUIO_CLK_STOP_CTL_2] = 0x00005f30,
[AST2700_SCUIO_CLK_SEL_1] = 0x86900000,
[AST2700_SCUIO_CLK_SEL_2] = 0x00400000,
[AST2700_SCUIO_HPLL_PARAM] = 0x10000027,
[AST2700_SCUIO_HPLL_EXT_PARAM] = 0x80000014,
[AST2700_SCUIO_APLL_PARAM] = 0x1000001f,
[AST2700_SCUIO_APLL_EXT_PARAM] = 0x8000000f,
[AST2700_SCUIO_DPLL_PARAM] = 0x106e42ce,
[AST2700_SCUIO_DPLL_EXT_PARAM] = 0x80000167,
[AST2700_SCUIO_DPLL_PARAM_READ] = 0x106e42ce,
[AST2700_SCUIO_DPLL_EXT_PARAM_READ] = 0x80000167,
[AST2700_SCUIO_UARTCLK_GEN] = 0x00014506,
[AST2700_SCUIO_HUARTCLK_GEN] = 0x000145c0,
[AST2700_SCUIO_CLK_DUTY_MEAS_RST] = 0x0c9100d2,
};
static void aspeed_2700_scuio_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass);
dc->desc = "ASPEED 2700 System Control Unit I/O";
dc->reset = aspeed_ast2700_scu_reset;
asc->resets = ast2700_a0_resets_io;
asc->calc_hpll = aspeed_2600_scu_calc_hpll;
asc->get_apb = aspeed_2700_scuio_get_apb_freq;
asc->apb_divider = 2;
asc->nr_regs = ASPEED_AST2700_SCU_NR_REGS;
asc->clkin_25Mhz = true;
asc->ops = &aspeed_ast2700_scuio_ops;
}
static const TypeInfo aspeed_2700_scu_info = {
.name = TYPE_ASPEED_2700_SCU,
.parent = TYPE_ASPEED_SCU,
.instance_size = sizeof(AspeedSCUState),
.class_init = aspeed_2700_scu_class_init,
};
static const TypeInfo aspeed_2700_scuio_info = {
.name = TYPE_ASPEED_2700_SCUIO,
.parent = TYPE_ASPEED_SCU,
.instance_size = sizeof(AspeedSCUState),
.class_init = aspeed_2700_scuio_class_init,
};
static const uint32_t ast1030_a1_resets[ASPEED_AST2600_SCU_NR_REGS] = {
[AST2600_SYS_RST_CTRL] = 0xFFC3FED8,
[AST2600_SYS_RST_CTRL2] = 0x09FFFFFC,
@ -841,6 +1143,8 @@ static void aspeed_scu_register_types(void)
type_register_static(&aspeed_2500_scu_info);
type_register_static(&aspeed_2600_scu_info);
type_register_static(&aspeed_1030_scu_info);
type_register_static(&aspeed_2700_scu_info);
type_register_static(&aspeed_2700_scuio_info);
}
type_init(aspeed_scu_register_types);

View File

@ -27,6 +27,7 @@
#define PROT_SOFTLOCKED 0x00
#define PROT_KEY_UNLOCK 0xFC600309
#define PROT_2700_KEY_UNLOCK 0x1688A8A8
#define PROT_KEY_HARDLOCK 0xDEADDEAD /* AST2600 */
/* Configuration Register */
@ -54,6 +55,46 @@
#define R_DRAM_TIME (0x8c / 4)
#define R_ECC_ERR_INJECT (0xb4 / 4)
/* AST2700 Register */
#define R_2700_PROT (0x00 / 4)
#define R_INT_STATUS (0x04 / 4)
#define R_INT_CLEAR (0x08 / 4)
#define R_INT_MASK (0x0c / 4)
#define R_MAIN_CONF (0x10 / 4)
#define R_MAIN_CONTROL (0x14 / 4)
#define R_MAIN_STATUS (0x18 / 4)
#define R_ERR_STATUS (0x1c / 4)
#define R_ECC_FAIL_STATUS (0x78 / 4)
#define R_ECC_FAIL_ADDR (0x7c / 4)
#define R_ECC_TESTING_CONTROL (0x80 / 4)
#define R_PROT_REGION_LOCK_STATUS (0x94 / 4)
#define R_TEST_FAIL_ADDR (0xd4 / 4)
#define R_TEST_FAIL_D0 (0xd8 / 4)
#define R_TEST_FAIL_D1 (0xdc / 4)
#define R_TEST_FAIL_D2 (0xe0 / 4)
#define R_TEST_FAIL_D3 (0xe4 / 4)
#define R_DBG_STATUS (0xf4 / 4)
#define R_PHY_INTERFACE_STATUS (0xf8 / 4)
#define R_GRAPHIC_MEM_BASE_ADDR (0x10c / 4)
#define R_PORT0_INTERFACE_MONITOR0 (0x240 / 4)
#define R_PORT0_INTERFACE_MONITOR1 (0x244 / 4)
#define R_PORT0_INTERFACE_MONITOR2 (0x248 / 4)
#define R_PORT1_INTERFACE_MONITOR0 (0x2c0 / 4)
#define R_PORT1_INTERFACE_MONITOR1 (0x2c4 / 4)
#define R_PORT1_INTERFACE_MONITOR2 (0x2c8 / 4)
#define R_PORT2_INTERFACE_MONITOR0 (0x340 / 4)
#define R_PORT2_INTERFACE_MONITOR1 (0x344 / 4)
#define R_PORT2_INTERFACE_MONITOR2 (0x348 / 4)
#define R_PORT3_INTERFACE_MONITOR0 (0x3c0 / 4)
#define R_PORT3_INTERFACE_MONITOR1 (0x3c4 / 4)
#define R_PORT3_INTERFACE_MONITOR2 (0x3c8 / 4)
#define R_PORT4_INTERFACE_MONITOR0 (0x440 / 4)
#define R_PORT4_INTERFACE_MONITOR1 (0x444 / 4)
#define R_PORT4_INTERFACE_MONITOR2 (0x448 / 4)
#define R_PORT5_INTERFACE_MONITOR0 (0x4c0 / 4)
#define R_PORT5_INTERFACE_MONITOR1 (0x4c4 / 4)
#define R_PORT5_INTERFACE_MONITOR2 (0x4c8 / 4)
/*
* Configuration register Ox4 (for Aspeed AST2400 SOC)
*
@ -76,10 +117,6 @@
#define ASPEED_SDMC_VGA_32MB 0x2
#define ASPEED_SDMC_VGA_64MB 0x3
#define ASPEED_SDMC_DRAM_SIZE(x) (x & 0x3)
#define ASPEED_SDMC_DRAM_64MB 0x0
#define ASPEED_SDMC_DRAM_128MB 0x1
#define ASPEED_SDMC_DRAM_256MB 0x2
#define ASPEED_SDMC_DRAM_512MB 0x3
#define ASPEED_SDMC_READONLY_MASK \
(ASPEED_SDMC_RESERVED | ASPEED_SDMC_VGA_COMPAT | \
@ -100,22 +137,24 @@
#define ASPEED_SDMC_CACHE_ENABLE (1 << 10) /* differs from AST2400 */
#define ASPEED_SDMC_DRAM_TYPE (1 << 4) /* differs from AST2400 */
/* DRAM size definitions differs */
#define ASPEED_SDMC_AST2500_128MB 0x0
#define ASPEED_SDMC_AST2500_256MB 0x1
#define ASPEED_SDMC_AST2500_512MB 0x2
#define ASPEED_SDMC_AST2500_1024MB 0x3
#define ASPEED_SDMC_AST2600_256MB 0x0
#define ASPEED_SDMC_AST2600_512MB 0x1
#define ASPEED_SDMC_AST2600_1024MB 0x2
#define ASPEED_SDMC_AST2600_2048MB 0x3
#define ASPEED_SDMC_AST2500_READONLY_MASK \
(ASPEED_SDMC_HW_VERSION(0xf) | ASPEED_SDMC_CACHE_INITIAL_DONE | \
ASPEED_SDMC_AST2500_RESERVED | ASPEED_SDMC_VGA_COMPAT | \
ASPEED_SDMC_VGA_APERTURE(ASPEED_SDMC_VGA_64MB))
/*
* Main Configuration register Ox10 (for Aspeed AST2700 SOC and higher)
*
*/
#define ASPEED_SDMC_AST2700_RESERVED 0xFFFF2082 /* 31:16, 13, 7, 1 */
#define ASPEED_SDMC_AST2700_DATA_SCRAMBLE (1 << 8)
#define ASPEED_SDMC_AST2700_ECC_ENABLE (1 << 6)
#define ASPEED_SDMC_AST2700_PAGE_MATCHING_ENABLE (1 << 5)
#define ASPEED_SDMC_AST2700_DRAM_SIZE(x) ((x & 0x7) << 2)
#define ASPEED_SDMC_AST2700_READONLY_MASK \
(ASPEED_SDMC_AST2700_RESERVED)
static uint64_t aspeed_sdmc_read(void *opaque, hwaddr addr, unsigned size)
{
AspeedSDMCState *s = ASPEED_SDMC(opaque);
@ -231,7 +270,7 @@ static void aspeed_sdmc_realize(DeviceState *dev, Error **errp)
AspeedSDMCState *s = ASPEED_SDMC(dev);
AspeedSDMCClass *asc = ASPEED_SDMC_GET_CLASS(s);
assert(asc->max_ram_size < 4 * GiB); /* 32-bit address bus */
assert(asc->max_ram_size < 4 * GiB || asc->is_bus64bit);
s->max_ram_size = asc->max_ram_size;
memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_sdmc_ops, s,
@ -241,8 +280,8 @@ static void aspeed_sdmc_realize(DeviceState *dev, Error **errp)
static const VMStateDescription vmstate_aspeed_sdmc = {
.name = "aspeed.sdmc",
.version_id = 1,
.minimum_version_id = 1,
.version_id = 2,
.minimum_version_id = 2,
.fields = (const VMStateField[]) {
VMSTATE_UINT32_ARRAY(regs, AspeedSDMCState, ASPEED_SDMC_NR_REGS),
VMSTATE_END_OF_LIST()
@ -251,6 +290,7 @@ static const VMStateDescription vmstate_aspeed_sdmc = {
static Property aspeed_sdmc_properties[] = {
DEFINE_PROP_UINT64("max-ram-size", AspeedSDMCState, max_ram_size, 0),
DEFINE_PROP_BOOL("unlocked", AspeedSDMCState, unlocked, false),
DEFINE_PROP_END_OF_LIST(),
};
@ -311,7 +351,8 @@ static void aspeed_2400_sdmc_write(AspeedSDMCState *s, uint32_t reg,
uint32_t data)
{
if (reg == R_PROT) {
s->regs[reg] = (data == PROT_KEY_UNLOCK) ? PROT_UNLOCKED : PROT_SOFTLOCKED;
s->regs[reg] =
(data == PROT_KEY_UNLOCK) ? PROT_UNLOCKED : PROT_SOFTLOCKED;
return;
}
@ -369,7 +410,8 @@ static void aspeed_2500_sdmc_write(AspeedSDMCState *s, uint32_t reg,
uint32_t data)
{
if (reg == R_PROT) {
s->regs[reg] = (data == PROT_KEY_UNLOCK) ? PROT_UNLOCKED : PROT_SOFTLOCKED;
s->regs[reg] =
(data == PROT_KEY_UNLOCK) ? PROT_UNLOCKED : PROT_SOFTLOCKED;
return;
}
@ -449,8 +491,9 @@ static void aspeed_2600_sdmc_write(AspeedSDMCState *s, uint32_t reg,
}
if (s->regs[R_PROT] == PROT_HARDLOCKED) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: SDMC is locked until system reset!\n",
__func__);
qemu_log_mask(LOG_GUEST_ERROR,
"%s: SDMC is locked until system reset!\n",
__func__);
return;
}
@ -512,12 +555,145 @@ static const TypeInfo aspeed_2600_sdmc_info = {
.class_init = aspeed_2600_sdmc_class_init,
};
static void aspeed_2700_sdmc_reset(DeviceState *dev)
{
AspeedSDMCState *s = ASPEED_SDMC(dev);
AspeedSDMCClass *asc = ASPEED_SDMC_GET_CLASS(s);
memset(s->regs, 0, sizeof(s->regs));
/* Set ram size bit and defaults values */
s->regs[R_MAIN_CONF] = asc->compute_conf(s, 0);
if (s->unlocked) {
s->regs[R_2700_PROT] = PROT_UNLOCKED;
}
}
static uint32_t aspeed_2700_sdmc_compute_conf(AspeedSDMCState *s, uint32_t data)
{
uint32_t fixed_conf = ASPEED_SDMC_AST2700_PAGE_MATCHING_ENABLE |
ASPEED_SDMC_AST2700_DRAM_SIZE(aspeed_sdmc_get_ram_bits(s));
/* Make sure readonly bits are kept */
data &= ~ASPEED_SDMC_AST2700_READONLY_MASK;
return data | fixed_conf;
}
static void aspeed_2700_sdmc_write(AspeedSDMCState *s, uint32_t reg,
uint32_t data)
{
/* Unprotected registers */
switch (reg) {
case R_INT_STATUS:
case R_INT_CLEAR:
case R_INT_MASK:
case R_MAIN_STATUS:
case R_ERR_STATUS:
case R_ECC_FAIL_STATUS:
case R_ECC_FAIL_ADDR:
case R_PROT_REGION_LOCK_STATUS:
case R_TEST_FAIL_ADDR:
case R_TEST_FAIL_D0:
case R_TEST_FAIL_D1:
case R_TEST_FAIL_D2:
case R_TEST_FAIL_D3:
case R_DBG_STATUS:
case R_PHY_INTERFACE_STATUS:
case R_GRAPHIC_MEM_BASE_ADDR:
case R_PORT0_INTERFACE_MONITOR0:
case R_PORT0_INTERFACE_MONITOR1:
case R_PORT0_INTERFACE_MONITOR2:
case R_PORT1_INTERFACE_MONITOR0:
case R_PORT1_INTERFACE_MONITOR1:
case R_PORT1_INTERFACE_MONITOR2:
case R_PORT2_INTERFACE_MONITOR0:
case R_PORT2_INTERFACE_MONITOR1:
case R_PORT2_INTERFACE_MONITOR2:
case R_PORT3_INTERFACE_MONITOR0:
case R_PORT3_INTERFACE_MONITOR1:
case R_PORT3_INTERFACE_MONITOR2:
case R_PORT4_INTERFACE_MONITOR0:
case R_PORT4_INTERFACE_MONITOR1:
case R_PORT4_INTERFACE_MONITOR2:
case R_PORT5_INTERFACE_MONITOR0:
case R_PORT5_INTERFACE_MONITOR1:
case R_PORT5_INTERFACE_MONITOR2:
s->regs[reg] = data;
return;
}
if (s->regs[R_2700_PROT] == PROT_HARDLOCKED) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: SDMC is locked until system reset!\n",
__func__);
return;
}
if (reg != R_2700_PROT && s->regs[R_2700_PROT] == PROT_SOFTLOCKED) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: SDMC is locked! (write to MCR%02x blocked)\n",
__func__, reg * 4);
return;
}
switch (reg) {
case R_2700_PROT:
if (data == PROT_2700_KEY_UNLOCK) {
data = PROT_UNLOCKED;
} else if (data == PROT_KEY_HARDLOCK) {
data = PROT_HARDLOCKED;
} else {
data = PROT_SOFTLOCKED;
}
break;
case R_MAIN_CONF:
data = aspeed_2700_sdmc_compute_conf(s, data);
break;
case R_MAIN_STATUS:
/* Will never return 'busy'. */
data &= ~PHY_BUSY_STATE;
break;
default:
break;
}
s->regs[reg] = data;
}
static const uint64_t
aspeed_2700_ram_sizes[] = { 256 * MiB, 512 * MiB, 1024 * MiB,
2048 * MiB, 4096 * MiB, 8192 * MiB, 0};
static void aspeed_2700_sdmc_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedSDMCClass *asc = ASPEED_SDMC_CLASS(klass);
dc->desc = "ASPEED 2700 SDRAM Memory Controller";
dc->reset = aspeed_2700_sdmc_reset;
asc->is_bus64bit = true;
asc->max_ram_size = 8 * GiB;
asc->compute_conf = aspeed_2700_sdmc_compute_conf;
asc->write = aspeed_2700_sdmc_write;
asc->valid_ram_sizes = aspeed_2700_ram_sizes;
}
static const TypeInfo aspeed_2700_sdmc_info = {
.name = TYPE_ASPEED_2700_SDMC,
.parent = TYPE_ASPEED_SDMC,
.class_init = aspeed_2700_sdmc_class_init,
};
static void aspeed_sdmc_register_types(void)
{
type_register_static(&aspeed_sdmc_info);
type_register_static(&aspeed_2400_sdmc_info);
type_register_static(&aspeed_2500_sdmc_info);
type_register_static(&aspeed_2600_sdmc_info);
type_register_static(&aspeed_2700_sdmc_info);
}
type_init(aspeed_sdmc_register_types);

177
hw/misc/aspeed_sli.c Normal file
View File

@ -0,0 +1,177 @@
/*
* ASPEED SLI Controller
*
* Copyright (C) 2024 ASPEED Technology Inc.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "qemu/error-report.h"
#include "hw/qdev-properties.h"
#include "hw/misc/aspeed_sli.h"
#include "qapi/error.h"
#include "migration/vmstate.h"
#include "trace.h"
#define SLI_REGION_SIZE 0x500
#define TO_REG(addr) ((addr) >> 2)
static uint64_t aspeed_sli_read(void *opaque, hwaddr addr, unsigned int size)
{
AspeedSLIState *s = ASPEED_SLI(opaque);
int reg = TO_REG(addr);
if (reg >= ARRAY_SIZE(s->regs)) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
__func__, addr);
return 0;
}
trace_aspeed_sli_read(addr, size, s->regs[reg]);
return s->regs[reg];
}
static void aspeed_sli_write(void *opaque, hwaddr addr, uint64_t data,
unsigned int size)
{
AspeedSLIState *s = ASPEED_SLI(opaque);
int reg = TO_REG(addr);
if (reg >= ARRAY_SIZE(s->regs)) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
__func__, addr);
return;
}
trace_aspeed_sli_write(addr, size, data);
s->regs[reg] = data;
}
static uint64_t aspeed_sliio_read(void *opaque, hwaddr addr, unsigned int size)
{
AspeedSLIState *s = ASPEED_SLI(opaque);
int reg = TO_REG(addr);
if (reg >= ARRAY_SIZE(s->regs)) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
__func__, addr);
return 0;
}
trace_aspeed_sliio_read(addr, size, s->regs[reg]);
return s->regs[reg];
}
static void aspeed_sliio_write(void *opaque, hwaddr addr, uint64_t data,
unsigned int size)
{
AspeedSLIState *s = ASPEED_SLI(opaque);
int reg = TO_REG(addr);
if (reg >= ARRAY_SIZE(s->regs)) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
__func__, addr);
return;
}
trace_aspeed_sliio_write(addr, size, data);
s->regs[reg] = data;
}
static const MemoryRegionOps aspeed_sli_ops = {
.read = aspeed_sli_read,
.write = aspeed_sli_write,
.endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 1,
.max_access_size = 4,
},
};
static const MemoryRegionOps aspeed_sliio_ops = {
.read = aspeed_sliio_read,
.write = aspeed_sliio_write,
.endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 1,
.max_access_size = 4,
},
};
static void aspeed_sli_realize(DeviceState *dev, Error **errp)
{
AspeedSLIState *s = ASPEED_SLI(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_sli_ops, s,
TYPE_ASPEED_SLI, SLI_REGION_SIZE);
sysbus_init_mmio(sbd, &s->iomem);
}
static void aspeed_sliio_realize(DeviceState *dev, Error **errp)
{
AspeedSLIState *s = ASPEED_SLI(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_sliio_ops, s,
TYPE_ASPEED_SLI, SLI_REGION_SIZE);
sysbus_init_mmio(sbd, &s->iomem);
}
static void aspeed_sli_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->desc = "Aspeed SLI Controller";
dc->realize = aspeed_sli_realize;
}
static const TypeInfo aspeed_sli_info = {
.name = TYPE_ASPEED_SLI,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(AspeedSLIState),
.class_init = aspeed_sli_class_init,
.abstract = true,
};
static void aspeed_2700_sli_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->desc = "AST2700 SLI Controller";
}
static void aspeed_2700_sliio_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->desc = "AST2700 I/O SLI Controller";
dc->realize = aspeed_sliio_realize;
}
static const TypeInfo aspeed_2700_sli_info = {
.name = TYPE_ASPEED_2700_SLI,
.parent = TYPE_ASPEED_SLI,
.class_init = aspeed_2700_sli_class_init,
};
static const TypeInfo aspeed_2700_sliio_info = {
.name = TYPE_ASPEED_2700_SLIIO,
.parent = TYPE_ASPEED_SLI,
.class_init = aspeed_2700_sliio_class_init,
};
static void aspeed_sli_register_types(void)
{
type_register_static(&aspeed_sli_info);
type_register_static(&aspeed_2700_sli_info);
type_register_static(&aspeed_2700_sliio_info);
}
type_init(aspeed_sli_register_types);

View File

@ -136,7 +136,8 @@ system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files(
'aspeed_sbc.c',
'aspeed_sdmc.c',
'aspeed_xdma.c',
'aspeed_peci.c'))
'aspeed_peci.c',
'aspeed_sli.c'))
system_ss.add(when: 'CONFIG_MSF2', if_true: files('msf2-sysreg.c'))
system_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_rng.c'))

View File

@ -93,6 +93,10 @@ slavio_led_mem_readw(uint32_t ret) "Read diagnostic LED 0x%04x"
# aspeed_scu.c
aspeed_scu_write(uint64_t offset, unsigned size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
aspeed_scu_read(uint64_t offset, unsigned size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
aspeed_ast2700_scu_write(uint64_t offset, unsigned size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
aspeed_ast2700_scu_read(uint64_t offset, unsigned size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
aspeed_ast2700_scuio_write(uint64_t offset, unsigned size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
aspeed_ast2700_scuio_read(uint64_t offset, unsigned size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
# mps2-scc.c
mps2_scc_read(uint64_t offset, uint64_t data, unsigned size) "MPS2 SCC read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
@ -351,3 +355,10 @@ djmemc_write(int reg, uint64_t value, unsigned int size) "reg=0x%x value=0x%"PRI
# iosb.c
iosb_read(int reg, uint64_t value, unsigned int size) "reg=0x%x value=0x%"PRIx64" size=%u"
iosb_write(int reg, uint64_t value, unsigned int size) "reg=0x%x value=0x%"PRIx64" size=%u"
# aspeed_sli.c
aspeed_sli_write(uint64_t offset, unsigned int size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
aspeed_sli_read(uint64_t offset, unsigned int size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
aspeed_sliio_write(uint64_t offset, unsigned int size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32
aspeed_sliio_read(uint64_t offset, unsigned int size, uint32_t data) "To 0x%" PRIx64 " of size %u: 0x%" PRIx32

View File

@ -132,6 +132,9 @@
#define FMC_WDT2_CTRL_BOOT_SOURCE BIT(4) /* O: primary 1: alternate */
#define FMC_WDT2_CTRL_EN BIT(0)
/* DMA DRAM Side Address High Part (AST2700) */
#define R_DMA_DRAM_ADDR_HIGH (0x7c / 4)
/* DMA Control/Status Register */
#define R_DMA_CTRL (0x80 / 4)
#define DMA_CTRL_REQUEST (1 << 31)
@ -178,13 +181,18 @@
* DMA flash addresses should be 4 bytes aligned and the valid address
* range is 0x20000000 - 0x2FFFFFFF.
*
* DMA length is from 4 bytes to 32MB
* DMA length is from 4 bytes to 32MB (AST2500)
* 0: 4 bytes
* 0x7FFFFF: 32M bytes
* 0x1FFFFFC: 32M bytes
*
* DMA length is from 1 byte to 32MB (AST2600, AST10x0 and AST2700)
* 0: 1 byte
* 0x1FFFFFF: 32M bytes
*/
#define DMA_DRAM_ADDR(asc, val) ((val) & (asc)->dma_dram_mask)
#define DMA_DRAM_ADDR_HIGH(val) ((val) & 0xf)
#define DMA_FLASH_ADDR(asc, val) ((val) & (asc)->dma_flash_mask)
#define DMA_LENGTH(val) ((val) & 0x01FFFFFC)
#define DMA_LENGTH(val) ((val) & 0x01FFFFFF)
/* Flash opcodes. */
#define SPI_OP_READ 0x03 /* Read data bytes (low frequency) */
@ -203,6 +211,7 @@ static const AspeedSegments aspeed_2500_spi2_segments[];
#define ASPEED_SMC_FEATURE_DMA 0x1
#define ASPEED_SMC_FEATURE_DMA_GRANT 0x2
#define ASPEED_SMC_FEATURE_WDT_CONTROL 0x4
#define ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH 0x08
static inline bool aspeed_smc_has_dma(const AspeedSMCClass *asc)
{
@ -214,6 +223,11 @@ static inline bool aspeed_smc_has_wdt_control(const AspeedSMCClass *asc)
return !!(asc->features & ASPEED_SMC_FEATURE_WDT_CONTROL);
}
static inline bool aspeed_smc_has_dma64(const AspeedSMCClass *asc)
{
return !!(asc->features & ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH);
}
#define aspeed_smc_error(fmt, ...) \
qemu_log_mask(LOG_GUEST_ERROR, "%s: " fmt "\n", __func__, ## __VA_ARGS__)
@ -743,6 +757,8 @@ static uint64_t aspeed_smc_read(void *opaque, hwaddr addr, unsigned int size)
(aspeed_smc_has_dma(asc) && addr == R_DMA_CTRL) ||
(aspeed_smc_has_dma(asc) && addr == R_DMA_FLASH_ADDR) ||
(aspeed_smc_has_dma(asc) && addr == R_DMA_DRAM_ADDR) ||
(aspeed_smc_has_dma(asc) && aspeed_smc_has_dma64(asc) &&
addr == R_DMA_DRAM_ADDR_HIGH) ||
(aspeed_smc_has_dma(asc) && addr == R_DMA_LEN) ||
(aspeed_smc_has_dma(asc) && addr == R_DMA_CHECKSUM) ||
(addr >= R_SEG_ADDR0 &&
@ -843,6 +859,19 @@ static bool aspeed_smc_inject_read_failure(AspeedSMCState *s)
}
}
static uint64_t aspeed_smc_dma_dram_addr(AspeedSMCState *s)
{
return s->regs[R_DMA_DRAM_ADDR] |
((uint64_t) s->regs[R_DMA_DRAM_ADDR_HIGH] << 32);
}
static uint32_t aspeed_smc_dma_len(AspeedSMCState *s)
{
AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s);
return QEMU_ALIGN_UP(s->regs[R_DMA_LEN] + asc->dma_start_length, 4);
}
/*
* Accumulate the result of the reads to provide a checksum that will
* be used to validate the read timing settings.
@ -850,6 +879,7 @@ static bool aspeed_smc_inject_read_failure(AspeedSMCState *s)
static void aspeed_smc_dma_checksum(AspeedSMCState *s)
{
MemTxResult result;
uint32_t dma_len;
uint32_t data;
if (s->regs[R_DMA_CTRL] & DMA_CTRL_WRITE) {
@ -861,7 +891,9 @@ static void aspeed_smc_dma_checksum(AspeedSMCState *s)
aspeed_smc_dma_calibration(s);
}
while (s->regs[R_DMA_LEN]) {
dma_len = aspeed_smc_dma_len(s);
while (dma_len) {
data = address_space_ldl_le(&s->flash_as, s->regs[R_DMA_FLASH_ADDR],
MEMTXATTRS_UNSPECIFIED, &result);
if (result != MEMTX_OK) {
@ -877,7 +909,8 @@ static void aspeed_smc_dma_checksum(AspeedSMCState *s)
*/
s->regs[R_DMA_CHECKSUM] += data;
s->regs[R_DMA_FLASH_ADDR] += 4;
s->regs[R_DMA_LEN] -= 4;
dma_len -= 4;
s->regs[R_DMA_LEN] = dma_len;
}
if (s->inject_failure && aspeed_smc_inject_read_failure(s)) {
@ -888,21 +921,34 @@ static void aspeed_smc_dma_checksum(AspeedSMCState *s)
static void aspeed_smc_dma_rw(AspeedSMCState *s)
{
AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s);
uint64_t dma_dram_offset;
uint64_t dma_dram_addr;
MemTxResult result;
uint32_t dma_len;
uint32_t data;
dma_len = aspeed_smc_dma_len(s);
dma_dram_addr = aspeed_smc_dma_dram_addr(s);
if (aspeed_smc_has_dma64(asc)) {
dma_dram_offset = dma_dram_addr - s->dram_base;
} else {
dma_dram_offset = dma_dram_addr;
}
trace_aspeed_smc_dma_rw(s->regs[R_DMA_CTRL] & DMA_CTRL_WRITE ?
"write" : "read",
s->regs[R_DMA_FLASH_ADDR],
s->regs[R_DMA_DRAM_ADDR],
s->regs[R_DMA_LEN]);
while (s->regs[R_DMA_LEN]) {
dma_dram_offset,
dma_len);
while (dma_len) {
if (s->regs[R_DMA_CTRL] & DMA_CTRL_WRITE) {
data = address_space_ldl_le(&s->dram_as, s->regs[R_DMA_DRAM_ADDR],
data = address_space_ldl_le(&s->dram_as, dma_dram_offset,
MEMTXATTRS_UNSPECIFIED, &result);
if (result != MEMTX_OK) {
aspeed_smc_error("DRAM read failed @%08x",
s->regs[R_DMA_DRAM_ADDR]);
aspeed_smc_error("DRAM read failed @%" PRIx64,
dma_dram_offset);
return;
}
@ -922,11 +968,11 @@ static void aspeed_smc_dma_rw(AspeedSMCState *s)
return;
}
address_space_stl_le(&s->dram_as, s->regs[R_DMA_DRAM_ADDR],
address_space_stl_le(&s->dram_as, dma_dram_offset,
data, MEMTXATTRS_UNSPECIFIED, &result);
if (result != MEMTX_OK) {
aspeed_smc_error("DRAM write failed @%08x",
s->regs[R_DMA_DRAM_ADDR]);
aspeed_smc_error("DRAM write failed @%" PRIx64,
dma_dram_offset);
return;
}
}
@ -935,9 +981,14 @@ static void aspeed_smc_dma_rw(AspeedSMCState *s)
* When the DMA is on-going, the DMA registers are updated
* with the current working addresses and length.
*/
dma_dram_offset += 4;
dma_dram_addr += 4;
s->regs[R_DMA_DRAM_ADDR_HIGH] = dma_dram_addr >> 32;
s->regs[R_DMA_DRAM_ADDR] = dma_dram_addr & 0xffffffff;
s->regs[R_DMA_FLASH_ADDR] += 4;
s->regs[R_DMA_DRAM_ADDR] += 4;
s->regs[R_DMA_LEN] -= 4;
dma_len -= 4;
s->regs[R_DMA_LEN] = dma_len;
s->regs[R_DMA_CHECKSUM] += data;
}
}
@ -1088,6 +1139,9 @@ static void aspeed_smc_write(void *opaque, hwaddr addr, uint64_t data,
} else if (aspeed_smc_has_dma(asc) && addr == R_DMA_LEN &&
aspeed_smc_dma_granted(s)) {
s->regs[addr] = DMA_LENGTH(value);
} else if (aspeed_smc_has_dma(asc) && aspeed_smc_has_dma64(asc) &&
addr == R_DMA_DRAM_ADDR_HIGH) {
s->regs[addr] = DMA_DRAM_ADDR_HIGH(value);
} else {
qemu_log_mask(LOG_UNIMP, "%s: not implemented: 0x%" HWADDR_PRIx "\n",
__func__, addr);
@ -1220,6 +1274,7 @@ static const VMStateDescription vmstate_aspeed_smc = {
static Property aspeed_smc_properties[] = {
DEFINE_PROP_BOOL("inject-failure", AspeedSMCState, inject_failure, false),
DEFINE_PROP_UINT64("dram-base", AspeedSMCState, dram_base, 0),
DEFINE_PROP_LINK("dram", AspeedSMCState, dram_mr,
TYPE_MEMORY_REGION, MemoryRegion *),
DEFINE_PROP_END_OF_LIST(),
@ -1261,7 +1316,7 @@ static void aspeed_smc_flash_realize(DeviceState *dev, Error **errp)
* Use the default segment value to size the memory region. This
* can be changed by FW at runtime.
*/
memory_region_init_io(&s->mmio, OBJECT(s), &aspeed_smc_flash_ops,
memory_region_init_io(&s->mmio, OBJECT(s), s->asc->reg_ops,
s, name, s->asc->segments[s->cs].size);
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
}
@ -1336,6 +1391,7 @@ static void aspeed_2400_smc_class_init(ObjectClass *klass, void *data)
asc->segment_to_reg = aspeed_smc_segment_to_reg;
asc->reg_to_segment = aspeed_smc_reg_to_segment;
asc->dma_ctrl = aspeed_smc_dma_ctrl;
asc->reg_ops = &aspeed_smc_flash_ops;
}
static const TypeInfo aspeed_2400_smc_info = {
@ -1381,10 +1437,12 @@ static void aspeed_2400_fmc_class_init(ObjectClass *klass, void *data)
asc->features = ASPEED_SMC_FEATURE_DMA;
asc->dma_flash_mask = 0x0FFFFFFC;
asc->dma_dram_mask = 0x1FFFFFFC;
asc->dma_start_length = 4;
asc->nregs = ASPEED_SMC_R_MAX;
asc->segment_to_reg = aspeed_smc_segment_to_reg;
asc->reg_to_segment = aspeed_smc_reg_to_segment;
asc->dma_ctrl = aspeed_smc_dma_ctrl;
asc->reg_ops = &aspeed_smc_flash_ops;
}
static const TypeInfo aspeed_2400_fmc_info = {
@ -1424,6 +1482,7 @@ static void aspeed_2400_spi1_class_init(ObjectClass *klass, void *data)
asc->reg_to_segment = aspeed_smc_reg_to_segment;
asc->dma_ctrl = aspeed_smc_dma_ctrl;
asc->addr_width = aspeed_2400_spi1_addr_width;
asc->reg_ops = &aspeed_smc_flash_ops;
}
static const TypeInfo aspeed_2400_spi1_info = {
@ -1448,7 +1507,7 @@ static void aspeed_2500_fmc_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass);
dc->desc = "Aspeed 2600 FMC Controller";
dc->desc = "Aspeed 2500 FMC Controller";
asc->r_conf = R_CONF;
asc->r_ce_ctrl = R_CE_CTRL;
asc->r_ctrl0 = R_CTRL0;
@ -1464,10 +1523,12 @@ static void aspeed_2500_fmc_class_init(ObjectClass *klass, void *data)
asc->features = ASPEED_SMC_FEATURE_DMA;
asc->dma_flash_mask = 0x0FFFFFFC;
asc->dma_dram_mask = 0x3FFFFFFC;
asc->dma_start_length = 4;
asc->nregs = ASPEED_SMC_R_MAX;
asc->segment_to_reg = aspeed_smc_segment_to_reg;
asc->reg_to_segment = aspeed_smc_reg_to_segment;
asc->dma_ctrl = aspeed_smc_dma_ctrl;
asc->reg_ops = &aspeed_smc_flash_ops;
}
static const TypeInfo aspeed_2500_fmc_info = {
@ -1486,7 +1547,7 @@ static void aspeed_2500_spi1_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass);
dc->desc = "Aspeed 2600 SPI1 Controller";
dc->desc = "Aspeed 2500 SPI1 Controller";
asc->r_conf = R_CONF;
asc->r_ce_ctrl = R_CE_CTRL;
asc->r_ctrl0 = R_CTRL0;
@ -1503,6 +1564,7 @@ static void aspeed_2500_spi1_class_init(ObjectClass *klass, void *data)
asc->segment_to_reg = aspeed_smc_segment_to_reg;
asc->reg_to_segment = aspeed_smc_reg_to_segment;
asc->dma_ctrl = aspeed_smc_dma_ctrl;
asc->reg_ops = &aspeed_smc_flash_ops;
}
static const TypeInfo aspeed_2500_spi1_info = {
@ -1521,7 +1583,7 @@ static void aspeed_2500_spi2_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass);
dc->desc = "Aspeed 2600 SPI2 Controller";
dc->desc = "Aspeed 2500 SPI2 Controller";
asc->r_conf = R_CONF;
asc->r_ce_ctrl = R_CE_CTRL;
asc->r_ctrl0 = R_CTRL0;
@ -1538,6 +1600,7 @@ static void aspeed_2500_spi2_class_init(ObjectClass *klass, void *data)
asc->segment_to_reg = aspeed_smc_segment_to_reg;
asc->reg_to_segment = aspeed_smc_reg_to_segment;
asc->dma_ctrl = aspeed_smc_dma_ctrl;
asc->reg_ops = &aspeed_smc_flash_ops;
}
static const TypeInfo aspeed_2500_spi2_info = {
@ -1620,10 +1683,12 @@ static void aspeed_2600_fmc_class_init(ObjectClass *klass, void *data)
ASPEED_SMC_FEATURE_WDT_CONTROL;
asc->dma_flash_mask = 0x0FFFFFFC;
asc->dma_dram_mask = 0x3FFFFFFC;
asc->dma_start_length = 1;
asc->nregs = ASPEED_SMC_R_MAX;
asc->segment_to_reg = aspeed_2600_smc_segment_to_reg;
asc->reg_to_segment = aspeed_2600_smc_reg_to_segment;
asc->dma_ctrl = aspeed_2600_smc_dma_ctrl;
asc->reg_ops = &aspeed_smc_flash_ops;
}
static const TypeInfo aspeed_2600_fmc_info = {
@ -1658,10 +1723,12 @@ static void aspeed_2600_spi1_class_init(ObjectClass *klass, void *data)
ASPEED_SMC_FEATURE_DMA_GRANT;
asc->dma_flash_mask = 0x0FFFFFFC;
asc->dma_dram_mask = 0x3FFFFFFC;
asc->dma_start_length = 1;
asc->nregs = ASPEED_SMC_R_MAX;
asc->segment_to_reg = aspeed_2600_smc_segment_to_reg;
asc->reg_to_segment = aspeed_2600_smc_reg_to_segment;
asc->dma_ctrl = aspeed_2600_smc_dma_ctrl;
asc->reg_ops = &aspeed_smc_flash_ops;
}
static const TypeInfo aspeed_2600_spi1_info = {
@ -1697,10 +1764,12 @@ static void aspeed_2600_spi2_class_init(ObjectClass *klass, void *data)
ASPEED_SMC_FEATURE_DMA_GRANT;
asc->dma_flash_mask = 0x0FFFFFFC;
asc->dma_dram_mask = 0x3FFFFFFC;
asc->dma_start_length = 1;
asc->nregs = ASPEED_SMC_R_MAX;
asc->segment_to_reg = aspeed_2600_smc_segment_to_reg;
asc->reg_to_segment = aspeed_2600_smc_reg_to_segment;
asc->dma_ctrl = aspeed_2600_smc_dma_ctrl;
asc->reg_ops = &aspeed_smc_flash_ops;
}
static const TypeInfo aspeed_2600_spi2_info = {
@ -1778,10 +1847,12 @@ static void aspeed_1030_fmc_class_init(ObjectClass *klass, void *data)
asc->features = ASPEED_SMC_FEATURE_DMA;
asc->dma_flash_mask = 0x0FFFFFFC;
asc->dma_dram_mask = 0x000BFFFC;
asc->dma_start_length = 1;
asc->nregs = ASPEED_SMC_R_MAX;
asc->segment_to_reg = aspeed_1030_smc_segment_to_reg;
asc->reg_to_segment = aspeed_1030_smc_reg_to_segment;
asc->dma_ctrl = aspeed_2600_smc_dma_ctrl;
asc->reg_ops = &aspeed_smc_flash_ops;
}
static const TypeInfo aspeed_1030_fmc_info = {
@ -1815,10 +1886,12 @@ static void aspeed_1030_spi1_class_init(ObjectClass *klass, void *data)
asc->features = ASPEED_SMC_FEATURE_DMA;
asc->dma_flash_mask = 0x0FFFFFFC;
asc->dma_dram_mask = 0x000BFFFC;
asc->dma_start_length = 1;
asc->nregs = ASPEED_SMC_R_MAX;
asc->segment_to_reg = aspeed_2600_smc_segment_to_reg;
asc->reg_to_segment = aspeed_2600_smc_reg_to_segment;
asc->dma_ctrl = aspeed_2600_smc_dma_ctrl;
asc->reg_ops = &aspeed_smc_flash_ops;
}
static const TypeInfo aspeed_1030_spi1_info = {
@ -1851,10 +1924,12 @@ static void aspeed_1030_spi2_class_init(ObjectClass *klass, void *data)
asc->features = ASPEED_SMC_FEATURE_DMA;
asc->dma_flash_mask = 0x0FFFFFFC;
asc->dma_dram_mask = 0x000BFFFC;
asc->dma_start_length = 1;
asc->nregs = ASPEED_SMC_R_MAX;
asc->segment_to_reg = aspeed_2600_smc_segment_to_reg;
asc->reg_to_segment = aspeed_2600_smc_reg_to_segment;
asc->dma_ctrl = aspeed_2600_smc_dma_ctrl;
asc->reg_ops = &aspeed_smc_flash_ops;
}
static const TypeInfo aspeed_1030_spi2_info = {
@ -1863,6 +1938,234 @@ static const TypeInfo aspeed_1030_spi2_info = {
.class_init = aspeed_1030_spi2_class_init,
};
/*
* The FMC Segment Registers of the AST2700 have a 64KB unit.
* Only bits [31:16] are used for decoding.
*/
#define AST2700_SEG_ADDR_MASK 0xffff0000
static uint32_t aspeed_2700_smc_segment_to_reg(const AspeedSMCState *s,
const AspeedSegments *seg)
{
uint32_t reg = 0;
/* Disabled segments have a nil register */
if (!seg->size) {
return 0;
}
reg |= (seg->addr & AST2700_SEG_ADDR_MASK) >> 16; /* start offset */
reg |= (seg->addr + seg->size - 1) & AST2700_SEG_ADDR_MASK; /* end offset */
return reg;
}
static void aspeed_2700_smc_reg_to_segment(const AspeedSMCState *s,
uint32_t reg, AspeedSegments *seg)
{
uint32_t start_offset = (reg << 16) & AST2700_SEG_ADDR_MASK;
uint32_t end_offset = reg & AST2700_SEG_ADDR_MASK;
AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s);
if (reg) {
seg->addr = asc->flash_window_base + start_offset;
seg->size = end_offset + (64 * KiB) - start_offset;
} else {
seg->addr = asc->flash_window_base;
seg->size = 0;
}
}
static const uint32_t aspeed_2700_fmc_resets[ASPEED_SMC_R_MAX] = {
[R_CONF] = (CONF_FLASH_TYPE_SPI << CONF_FLASH_TYPE0 |
CONF_FLASH_TYPE_SPI << CONF_FLASH_TYPE1),
[R_CE_CTRL] = 0x0000aa00,
[R_CTRL0] = 0x406b0641,
[R_CTRL1] = 0x00000400,
[R_CTRL2] = 0x00000400,
[R_CTRL3] = 0x00000400,
[R_SEG_ADDR0] = 0x08000000,
[R_SEG_ADDR1] = 0x10000800,
[R_SEG_ADDR2] = 0x00000000,
[R_SEG_ADDR3] = 0x00000000,
[R_DUMMY_DATA] = 0x00010000,
[R_DMA_DRAM_ADDR_HIGH] = 0x00000000,
[R_TIMINGS] = 0x007b0000,
};
static const MemoryRegionOps aspeed_2700_smc_flash_ops = {
.read = aspeed_smc_flash_read,
.write = aspeed_smc_flash_write,
.endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 1,
.max_access_size = 8,
},
};
static const AspeedSegments aspeed_2700_fmc_segments[] = {
{ 0x0, 128 * MiB }, /* start address is readonly */
{ 128 * MiB, 128 * MiB }, /* default is disabled but needed for -kernel */
{ 256 * MiB, 128 * MiB }, /* default is disabled but needed for -kernel */
{ 0x0, 0 }, /* disabled */
};
static void aspeed_2700_fmc_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass);
dc->desc = "Aspeed 2700 FMC Controller";
asc->r_conf = R_CONF;
asc->r_ce_ctrl = R_CE_CTRL;
asc->r_ctrl0 = R_CTRL0;
asc->r_timings = R_TIMINGS;
asc->nregs_timings = 3;
asc->conf_enable_w0 = CONF_ENABLE_W0;
asc->cs_num_max = 3;
asc->segments = aspeed_2700_fmc_segments;
asc->segment_addr_mask = 0xffffffff;
asc->resets = aspeed_2700_fmc_resets;
asc->flash_window_base = 0x100000000;
asc->flash_window_size = 1 * GiB;
asc->features = ASPEED_SMC_FEATURE_DMA |
ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH;
asc->dma_flash_mask = 0x2FFFFFFC;
asc->dma_dram_mask = 0xFFFFFFFC;
asc->dma_start_length = 1;
asc->nregs = ASPEED_SMC_R_MAX;
asc->segment_to_reg = aspeed_2700_smc_segment_to_reg;
asc->reg_to_segment = aspeed_2700_smc_reg_to_segment;
asc->dma_ctrl = aspeed_2600_smc_dma_ctrl;
asc->reg_ops = &aspeed_2700_smc_flash_ops;
}
static const TypeInfo aspeed_2700_fmc_info = {
.name = "aspeed.fmc-ast2700",
.parent = TYPE_ASPEED_SMC,
.class_init = aspeed_2700_fmc_class_init,
};
static const AspeedSegments aspeed_2700_spi0_segments[] = {
{ 0x0, 128 * MiB }, /* start address is readonly */
{ 128 * MiB, 128 * MiB }, /* start address is readonly */
{ 0x0, 0 }, /* disabled */
};
static void aspeed_2700_spi0_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass);
dc->desc = "Aspeed 2700 SPI0 Controller";
asc->r_conf = R_CONF;
asc->r_ce_ctrl = R_CE_CTRL;
asc->r_ctrl0 = R_CTRL0;
asc->r_timings = R_TIMINGS;
asc->nregs_timings = 2;
asc->conf_enable_w0 = CONF_ENABLE_W0;
asc->cs_num_max = 2;
asc->segments = aspeed_2700_spi0_segments;
asc->segment_addr_mask = 0xffffffff;
asc->flash_window_base = 0x180000000;
asc->flash_window_size = 1 * GiB;
asc->features = ASPEED_SMC_FEATURE_DMA |
ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH;
asc->dma_flash_mask = 0x2FFFFFFC;
asc->dma_dram_mask = 0xFFFFFFFC;
asc->dma_start_length = 1;
asc->nregs = ASPEED_SMC_R_MAX;
asc->segment_to_reg = aspeed_2700_smc_segment_to_reg;
asc->reg_to_segment = aspeed_2700_smc_reg_to_segment;
asc->dma_ctrl = aspeed_2600_smc_dma_ctrl;
asc->reg_ops = &aspeed_2700_smc_flash_ops;
}
static const TypeInfo aspeed_2700_spi0_info = {
.name = "aspeed.spi0-ast2700",
.parent = TYPE_ASPEED_SMC,
.class_init = aspeed_2700_spi0_class_init,
};
static const AspeedSegments aspeed_2700_spi1_segments[] = {
{ 0x0, 128 * MiB }, /* start address is readonly */
{ 0x0, 0 }, /* disabled */
};
static void aspeed_2700_spi1_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass);
dc->desc = "Aspeed 2700 SPI1 Controller";
asc->r_conf = R_CONF;
asc->r_ce_ctrl = R_CE_CTRL;
asc->r_ctrl0 = R_CTRL0;
asc->r_timings = R_TIMINGS;
asc->nregs_timings = 2;
asc->conf_enable_w0 = CONF_ENABLE_W0;
asc->cs_num_max = 2;
asc->segments = aspeed_2700_spi1_segments;
asc->segment_addr_mask = 0xffffffff;
asc->flash_window_base = 0x200000000;
asc->flash_window_size = 1 * GiB;
asc->features = ASPEED_SMC_FEATURE_DMA |
ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH;
asc->dma_flash_mask = 0x2FFFFFFC;
asc->dma_dram_mask = 0xFFFFFFFC;
asc->dma_start_length = 1;
asc->nregs = ASPEED_SMC_R_MAX;
asc->segment_to_reg = aspeed_2700_smc_segment_to_reg;
asc->reg_to_segment = aspeed_2700_smc_reg_to_segment;
asc->dma_ctrl = aspeed_2600_smc_dma_ctrl;
asc->reg_ops = &aspeed_2700_smc_flash_ops;
}
static const TypeInfo aspeed_2700_spi1_info = {
.name = "aspeed.spi1-ast2700",
.parent = TYPE_ASPEED_SMC,
.class_init = aspeed_2700_spi1_class_init,
};
static const AspeedSegments aspeed_2700_spi2_segments[] = {
{ 0x0, 128 * MiB }, /* start address is readonly */
{ 0x0, 0 }, /* disabled */
};
static void aspeed_2700_spi2_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass);
dc->desc = "Aspeed 2700 SPI2 Controller";
asc->r_conf = R_CONF;
asc->r_ce_ctrl = R_CE_CTRL;
asc->r_ctrl0 = R_CTRL0;
asc->r_timings = R_TIMINGS;
asc->nregs_timings = 2;
asc->conf_enable_w0 = CONF_ENABLE_W0;
asc->cs_num_max = 2;
asc->segments = aspeed_2700_spi2_segments;
asc->segment_addr_mask = 0xffffffff;
asc->flash_window_base = 0x280000000;
asc->flash_window_size = 1 * GiB;
asc->features = ASPEED_SMC_FEATURE_DMA |
ASPEED_SMC_FEATURE_DMA_DRAM_ADDR_HIGH;
asc->dma_flash_mask = 0x0FFFFFFC;
asc->dma_dram_mask = 0xFFFFFFFC;
asc->dma_start_length = 1;
asc->nregs = ASPEED_SMC_R_MAX;
asc->segment_to_reg = aspeed_2700_smc_segment_to_reg;
asc->reg_to_segment = aspeed_2700_smc_reg_to_segment;
asc->dma_ctrl = aspeed_2600_smc_dma_ctrl;
asc->reg_ops = &aspeed_2700_smc_flash_ops;
}
static const TypeInfo aspeed_2700_spi2_info = {
.name = "aspeed.spi2-ast2700",
.parent = TYPE_ASPEED_SMC,
.class_init = aspeed_2700_spi2_class_init,
};
static void aspeed_smc_register_types(void)
{
type_register_static(&aspeed_smc_flash_info);
@ -1879,6 +2182,10 @@ static void aspeed_smc_register_types(void)
type_register_static(&aspeed_1030_fmc_info);
type_register_static(&aspeed_1030_spi1_info);
type_register_static(&aspeed_1030_spi2_info);
type_register_static(&aspeed_2700_fmc_info);
type_register_static(&aspeed_2700_spi0_info);
type_register_static(&aspeed_2700_spi1_info);
type_register_static(&aspeed_2700_spi2_info);
}
type_init(aspeed_smc_register_types)

View File

@ -6,7 +6,7 @@ aspeed_smc_do_snoop(int cs, int index, int dummies, int data) "CS%d index:0x%x d
aspeed_smc_flash_write(int cs, uint64_t addr, uint32_t size, uint64_t data, int mode) "CS%d @0x%" PRIx64 " size %u: 0x%" PRIx64" mode:%d"
aspeed_smc_read(uint64_t addr, uint32_t size, uint64_t data) "@0x%" PRIx64 " size %u: 0x%" PRIx64
aspeed_smc_dma_checksum(uint32_t addr, uint32_t data) "0x%08x: 0x%08x"
aspeed_smc_dma_rw(const char *dir, uint32_t flash_addr, uint32_t dram_addr, uint32_t size) "%s flash:@0x%08x dram:@0x%08x size:0x%08x"
aspeed_smc_dma_rw(const char *dir, uint32_t flash_addr, uint64_t dram_addr, uint32_t size) "%s flash:@0x%08x dram:@0x%" PRIx64 " size:0x%08x"
aspeed_smc_write(uint64_t addr, uint32_t size, uint64_t data) "@0x%" PRIx64 " size %u: 0x%" PRIx64
aspeed_smc_flash_select(int cs, const char *prefix) "CS%d %sselect"

View File

@ -422,12 +422,36 @@ static const TypeInfo aspeed_1030_wdt_info = {
.class_init = aspeed_1030_wdt_class_init,
};
static void aspeed_2700_wdt_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedWDTClass *awc = ASPEED_WDT_CLASS(klass);
dc->desc = "ASPEED 2700 Watchdog Controller";
awc->iosize = 0x80;
awc->ext_pulse_width_mask = 0xfffff; /* TODO */
awc->reset_ctrl_reg = AST2600_SCU_RESET_CONTROL1;
awc->reset_pulse = aspeed_2500_wdt_reset_pulse;
awc->wdt_reload = aspeed_wdt_reload_1mhz;
awc->sanitize_ctrl = aspeed_2600_sanitize_ctrl;
awc->default_status = 0x014FB180;
awc->default_reload_value = 0x014FB180;
}
static const TypeInfo aspeed_2700_wdt_info = {
.name = TYPE_ASPEED_2700_WDT,
.parent = TYPE_ASPEED_WDT,
.instance_size = sizeof(AspeedWDTState),
.class_init = aspeed_2700_wdt_class_init,
};
static void wdt_aspeed_register_types(void)
{
type_register_static(&aspeed_wdt_info);
type_register_static(&aspeed_2400_wdt_info);
type_register_static(&aspeed_2500_wdt_info);
type_register_static(&aspeed_2600_wdt_info);
type_register_static(&aspeed_2700_wdt_info);
type_register_static(&aspeed_1030_wdt_info);
}

View File

@ -15,6 +15,7 @@
#include "hw/cpu/a15mpcore.h"
#include "hw/arm/armv7m.h"
#include "hw/intc/aspeed_vic.h"
#include "hw/intc/aspeed_intc.h"
#include "hw/misc/aspeed_scu.h"
#include "hw/adc/aspeed_adc.h"
#include "hw/misc/aspeed_sdmc.h"
@ -26,6 +27,7 @@
#include "hw/ssi/aspeed_smc.h"
#include "hw/misc/aspeed_hace.h"
#include "hw/misc/aspeed_sbc.h"
#include "hw/misc/aspeed_sli.h"
#include "hw/watchdog/wdt_aspeed.h"
#include "hw/net/ftgmac100.h"
#include "target/arm/cpu.h"
@ -38,11 +40,12 @@
#include "hw/misc/aspeed_peci.h"
#include "hw/fsi/aspeed_apb2opb.h"
#include "hw/char/serial.h"
#include "hw/intc/arm_gicv3.h"
#define ASPEED_SPIS_NUM 2
#define ASPEED_EHCIS_NUM 2
#define ASPEED_WDTS_NUM 4
#define ASPEED_CPUS_NUM 2
#define ASPEED_WDTS_NUM 8
#define ASPEED_CPUS_NUM 4
#define ASPEED_MACS_NUM 4
#define ASPEED_UARTS_NUM 13
#define ASPEED_JTAG_NUM 2
@ -56,11 +59,13 @@ struct AspeedSoCState {
MemoryRegion sram;
MemoryRegion spi_boot_container;
MemoryRegion spi_boot;
AddressSpace dram_as;
AspeedRtcState rtc;
AspeedTimerCtrlState timerctrl;
AspeedI2CState i2c;
AspeedI3CState i3c;
AspeedSCUState scu;
AspeedSCUState scuio;
AspeedHACEState hace;
AspeedXDMAState xdma;
AspeedADCState adc;
@ -68,6 +73,8 @@ struct AspeedSoCState {
AspeedSMCState spi[ASPEED_SPIS_NUM];
EHCISysBusState ehci[ASPEED_EHCIS_NUM];
AspeedSBCState sbc;
AspeedSLIState sli;
AspeedSLIState sliio;
MemoryRegion secsram;
UnimplementedDeviceState sbc_unimplemented;
AspeedSDMCState sdmc;
@ -117,6 +124,18 @@ struct Aspeed2600SoCState {
#define TYPE_ASPEED2600_SOC "aspeed2600-soc"
OBJECT_DECLARE_SIMPLE_TYPE(Aspeed2600SoCState, ASPEED2600_SOC)
struct Aspeed27x0SoCState {
AspeedSoCState parent;
ARMCPU cpu[ASPEED_CPUS_NUM];
AspeedINTCState intc;
GICv3State gic;
MemoryRegion dram_empty;
};
#define TYPE_ASPEED27X0_SOC "aspeed27x0-soc"
OBJECT_DECLARE_SIMPLE_TYPE(Aspeed27x0SoCState, ASPEED27X0_SOC)
struct Aspeed10x0SoCState {
AspeedSoCState parent;
@ -168,11 +187,13 @@ enum {
ASPEED_DEV_UART13,
ASPEED_DEV_VUART,
ASPEED_DEV_FMC,
ASPEED_DEV_SPI0,
ASPEED_DEV_SPI1,
ASPEED_DEV_SPI2,
ASPEED_DEV_EHCI1,
ASPEED_DEV_EHCI2,
ASPEED_DEV_VIC,
ASPEED_DEV_INTC,
ASPEED_DEV_SDMC,
ASPEED_DEV_SCU,
ASPEED_DEV_ADC,
@ -222,6 +243,11 @@ enum {
ASPEED_DEV_JTAG1,
ASPEED_DEV_FSI1,
ASPEED_DEV_FSI2,
ASPEED_DEV_SCUIO,
ASPEED_DEV_SLI,
ASPEED_DEV_SLIIO,
ASPEED_GIC_DIST,
ASPEED_GIC_REDIST,
};
qemu_irq aspeed_soc_get_irq(AspeedSoCState *s, int dev);

View File

@ -0,0 +1,44 @@
/*
* ASPEED INTC Controller
*
* Copyright (C) 2024 ASPEED Technology Inc.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef ASPEED_INTC_H
#define ASPEED_INTC_H
#include "hw/sysbus.h"
#include "qom/object.h"
#include "hw/or-irq.h"
#define TYPE_ASPEED_INTC "aspeed.intc"
#define TYPE_ASPEED_2700_INTC TYPE_ASPEED_INTC "-ast2700"
OBJECT_DECLARE_TYPE(AspeedINTCState, AspeedINTCClass, ASPEED_INTC)
#define ASPEED_INTC_NR_REGS (0x2000 >> 2)
#define ASPEED_INTC_NR_INTS 9
struct AspeedINTCState {
/*< private >*/
SysBusDevice parent_obj;
/*< public >*/
MemoryRegion iomem;
uint32_t regs[ASPEED_INTC_NR_REGS];
OrIRQState orgates[ASPEED_INTC_NR_INTS];
qemu_irq output_pins[ASPEED_INTC_NR_INTS];
uint32_t enable[ASPEED_INTC_NR_INTS];
uint32_t mask[ASPEED_INTC_NR_INTS];
uint32_t pending[ASPEED_INTC_NR_INTS];
};
struct AspeedINTCClass {
SysBusDeviceClass parent_class;
uint32_t num_lines;
uint32_t num_ints;
};
#endif /* ASPEED_INTC_H */

View File

@ -19,10 +19,13 @@ OBJECT_DECLARE_TYPE(AspeedSCUState, AspeedSCUClass, ASPEED_SCU)
#define TYPE_ASPEED_2400_SCU TYPE_ASPEED_SCU "-ast2400"
#define TYPE_ASPEED_2500_SCU TYPE_ASPEED_SCU "-ast2500"
#define TYPE_ASPEED_2600_SCU TYPE_ASPEED_SCU "-ast2600"
#define TYPE_ASPEED_2700_SCU TYPE_ASPEED_SCU "-ast2700"
#define TYPE_ASPEED_2700_SCUIO TYPE_ASPEED_SCU "io" "-ast2700"
#define TYPE_ASPEED_1030_SCU TYPE_ASPEED_SCU "-ast1030"
#define ASPEED_SCU_NR_REGS (0x1A8 >> 2)
#define ASPEED_AST2600_SCU_NR_REGS (0xE20 >> 2)
#define ASPEED_AST2700_SCU_NR_REGS (0xE20 >> 2)
struct AspeedSCUState {
/*< private >*/
@ -31,7 +34,7 @@ struct AspeedSCUState {
/*< public >*/
MemoryRegion iomem;
uint32_t regs[ASPEED_AST2600_SCU_NR_REGS];
uint32_t regs[ASPEED_AST2700_SCU_NR_REGS];
uint32_t silicon_rev;
uint32_t hw_strap1;
uint32_t hw_strap2;
@ -48,6 +51,9 @@ struct AspeedSCUState {
#define AST2600_A3_SILICON_REV 0x05030303U
#define AST1030_A0_SILICON_REV 0x80000000U
#define AST1030_A1_SILICON_REV 0x80010000U
#define AST2700_A0_SILICON_REV 0x06000103U
#define AST2720_A0_SILICON_REV 0x06000203U
#define AST2750_A0_SILICON_REV 0x06000003U
#define ASPEED_IS_AST2500(si_rev) ((((si_rev) >> 24) & 0xff) == 0x04)
@ -87,7 +93,8 @@ uint32_t aspeed_scu_get_apb_freq(AspeedSCUState *s);
* 1. 2012/12/29 Ryan Chen Create
*/
/* SCU08 Clock Selection Register
/*
* SCU08 Clock Selection Register
*
* 31 Enable Video Engine clock dynamic slow down
* 30:28 Video Engine clock slow down setting
@ -109,7 +116,8 @@ uint32_t aspeed_scu_get_apb_freq(AspeedSCUState *s);
*/
#define SCU_CLK_GET_PCLK_DIV(x) (((x) >> 23) & 0x7)
/* SCU24 H-PLL Parameter Register (for Aspeed AST2400 SOC)
/*
* SCU24 H-PLL Parameter Register (for Aspeed AST2400 SOC)
*
* 18 H-PLL parameter selection
* 0: Select H-PLL by strapping resistors
@ -127,7 +135,8 @@ uint32_t aspeed_scu_get_apb_freq(AspeedSCUState *s);
#define SCU_AST2400_H_PLL_BYPASS_EN (0x1 << 17)
#define SCU_AST2400_H_PLL_OFF (0x1 << 16)
/* SCU24 H-PLL Parameter Register (for Aspeed AST2500 SOC)
/*
* SCU24 H-PLL Parameter Register (for Aspeed AST2500 SOC)
*
* 21 Enable H-PLL reset
* 20 Enable H-PLL bypass mode
@ -144,7 +153,8 @@ uint32_t aspeed_scu_get_apb_freq(AspeedSCUState *s);
#define SCU_H_PLL_BYPASS_EN (0x1 << 20)
#define SCU_H_PLL_OFF (0x1 << 19)
/* SCU70 Hardware Strapping Register definition (for Aspeed AST2400 SOC)
/*
* SCU70 Hardware Strapping Register definition (for Aspeed AST2400 SOC)
*
* 31:29 Software defined strapping registers
* 28:27 DRAM size setting (for VGA driver use)
@ -361,4 +371,31 @@ uint32_t aspeed_scu_get_apb_freq(AspeedSCUState *s);
*/
#define SCU_AST1030_CLK_GET_PCLK_DIV(x) (((x) >> 8) & 0xf)
/*
* SCU280 Clock Selection 1 Register (for Aspeed AST2700 SCUIO)
*
* 31:29 MHCLK_DIV
* 28 Reserved
* 27:25 RGMIICLK_DIV
* 24 Reserved
* 23:21 RMIICLK_DIV
* 20:18 PCLK_DIV
* 17:14 SDCLK_DIV
* 13 SDCLK_SEL
* 12 UART13CLK_SEL
* 11 UART12CLK_SEL
* 10 UART11CLK_SEL
* 9 UART10CLK_SEL
* 8 UART9CLK_SEL
* 7 UART8CLK_SEL
* 6 UART7CLK_SEL
* 5 UART6CLK_SEL
* 4 UARTDBCLK_SEL
* 3 UART4CLK_SEL
* 2 UART3CLK_SEL
* 1 UART2CLK_SEL
* 0 UART1CLK_SEL
*/
#define SCUIO_AST2700_CLK_GET_PCLK_DIV(x) (((x) >> 18) & 0x7)
#endif /* ASPEED_SCU_H */

View File

@ -17,6 +17,7 @@ OBJECT_DECLARE_TYPE(AspeedSDMCState, AspeedSDMCClass, ASPEED_SDMC)
#define TYPE_ASPEED_2400_SDMC TYPE_ASPEED_SDMC "-ast2400"
#define TYPE_ASPEED_2500_SDMC TYPE_ASPEED_SDMC "-ast2500"
#define TYPE_ASPEED_2600_SDMC TYPE_ASPEED_SDMC "-ast2600"
#define TYPE_ASPEED_2700_SDMC TYPE_ASPEED_SDMC "-ast2700"
/*
* SDMC has 174 documented registers. In addition the u-boot device tree
@ -29,7 +30,7 @@ OBJECT_DECLARE_TYPE(AspeedSDMCState, AspeedSDMCClass, ASPEED_SDMC)
* time, and the other is in the DDR-PHY IP which is used during DDR-PHY
* training.
*/
#define ASPEED_SDMC_NR_REGS (0x500 >> 2)
#define ASPEED_SDMC_NR_REGS (0x1000 >> 2)
struct AspeedSDMCState {
/*< private >*/
@ -41,6 +42,7 @@ struct AspeedSDMCState {
uint32_t regs[ASPEED_SDMC_NR_REGS];
uint64_t ram_size;
uint64_t max_ram_size;
bool unlocked;
};
@ -51,6 +53,7 @@ struct AspeedSDMCClass {
const uint64_t *valid_ram_sizes;
uint32_t (*compute_conf)(AspeedSDMCState *s, uint32_t data);
void (*write)(AspeedSDMCState *s, uint32_t reg, uint32_t data);
bool is_bus64bit;
};
#endif /* ASPEED_SDMC_H */

View File

@ -0,0 +1,27 @@
/*
* ASPEED SLI Controller
*
* Copyright (C) 2024 ASPEED Technology Inc.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef ASPEED_SLI_H
#define ASPEED_SLI_H
#include "hw/sysbus.h"
#define TYPE_ASPEED_SLI "aspeed.sli"
#define TYPE_ASPEED_2700_SLI TYPE_ASPEED_SLI "-ast2700"
#define TYPE_ASPEED_2700_SLIIO TYPE_ASPEED_SLI "io" "-ast2700"
OBJECT_DECLARE_SIMPLE_TYPE(AspeedSLIState, ASPEED_SLI)
#define ASPEED_SLI_NR_REGS (0x500 >> 2)
struct AspeedSLIState {
SysBusDevice parent;
MemoryRegion iomem;
uint32_t regs[ASPEED_SLI_NR_REGS];
};
#endif /* ASPEED_SLI_H */

View File

@ -76,6 +76,7 @@ struct AspeedSMCState {
AddressSpace flash_as;
MemoryRegion *dram_mr;
AddressSpace dram_as;
uint64_t dram_base;
AspeedSMCFlash flashes[ASPEED_SMC_CS_MAX];
@ -106,6 +107,7 @@ struct AspeedSMCClass {
uint32_t features;
hwaddr dma_flash_mask;
hwaddr dma_dram_mask;
uint32_t dma_start_length;
uint32_t nregs;
uint32_t (*segment_to_reg)(const AspeedSMCState *s,
const AspeedSegments *seg);
@ -113,6 +115,7 @@ struct AspeedSMCClass {
AspeedSegments *seg);
void (*dma_ctrl)(AspeedSMCState *s, uint32_t value);
int (*addr_width)(const AspeedSMCState *s);
const MemoryRegionOps *reg_ops;
};
#endif /* ASPEED_SMC_H */

View File

@ -19,9 +19,10 @@ OBJECT_DECLARE_TYPE(AspeedWDTState, AspeedWDTClass, ASPEED_WDT)
#define TYPE_ASPEED_2400_WDT TYPE_ASPEED_WDT "-ast2400"
#define TYPE_ASPEED_2500_WDT TYPE_ASPEED_WDT "-ast2500"
#define TYPE_ASPEED_2600_WDT TYPE_ASPEED_WDT "-ast2600"
#define TYPE_ASPEED_2700_WDT TYPE_ASPEED_WDT "-ast2700"
#define TYPE_ASPEED_1030_WDT TYPE_ASPEED_WDT "-ast1030"
#define ASPEED_WDT_REGS_MAX (0x30 / 4)
#define ASPEED_WDT_REGS_MAX (0x80 / 4)
struct AspeedWDTState {
/*< private >*/

View File

@ -311,6 +311,17 @@ class AST2x00MachineSDK(QemuSystemTest, LinuxSSHMixIn):
self, 'boot', '## Loading kernel from FIT Image')
self.wait_for_console_pattern('Starting kernel ...')
def do_test_aarch64_aspeed_sdk_start(self, image):
self.vm.set_console()
self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw')
self.vm.launch()
self.wait_for_console_pattern('U-Boot 2023.10')
self.wait_for_console_pattern('## Loading kernel from FIT Image')
self.wait_for_console_pattern('Starting kernel ...')
self.wait_for_console_pattern("systemd[1]: Hostname set to")
@skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
def test_arm_ast2500_evb_sdk(self):
@ -375,3 +386,54 @@ class AST2x00MachineSDK(QemuSystemTest, LinuxSSHMixIn):
'i2c i2c-5: new_device: Instantiated device ds1307 at 0x32');
year = time.strftime("%Y")
self.ssh_command_output_contains('/sbin/hwclock -f /dev/rtc1', year);
def test_aarch64_ast2700_evb_sdk_v09_01(self):
"""
:avocado: tags=arch:aarch64
:avocado: tags=machine:ast2700-evb
"""
image_url = ('https://github.com/AspeedTech-BMC/openbmc/releases/'
'download/v09.01/ast2700-default-obmc.tar.gz')
image_hash = 'b1cc0fd73c7650d34c9c8459a243f52a91e9e27144b8608b2645ab19461d1e07'
image_path = self.fetch_asset(image_url, asset_hash=image_hash,
algorithm='sha256')
archive.extract(image_path, self.workdir)
num_cpu = 4
image_dir = self.workdir + '/ast2700-default/'
uboot_size = os.path.getsize(image_dir + 'u-boot-nodtb.bin')
uboot_dtb_load_addr = hex(0x400000000 + uboot_size)
load_images_list = [
{
'addr': '0x400000000',
'file': image_dir + 'u-boot-nodtb.bin'
},
{
'addr': str(uboot_dtb_load_addr),
'file': image_dir + 'u-boot.dtb'
},
{
'addr': '0x430000000',
'file': image_dir + 'bl31.bin'
},
{
'addr': '0x430080000',
'file': image_dir + 'optee/tee-raw.bin'
}
]
for load_image in load_images_list:
addr = load_image['addr']
file = load_image['file']
self.vm.add_args('-device',
f'loader,force-raw=on,addr={addr},file={file}')
for i in range(num_cpu):
self.vm.add_args('-device',
f'loader,addr=0x430000000,cpu-num={i}')
self.vm.add_args('-smp', str(num_cpu))
self.do_test_aarch64_aspeed_sdk_start(image_dir + 'image-bmc')