qemu/hw/arm/aspeed_ast2600.c
Peter Delevoryas 55c57023b7 hw/misc/aspeed: Add PECI controller
This introduces a really basic PECI controller that responses to
commands by always setting the response code to success and then raising
an interrupt to indicate the command is done. This helps avoid getting
hit with constant errors if the driver continuously attempts to send a
command and keeps timing out.

The AST2400 and AST2500 only included registers up to 0x5C, not 0xFC.
They supported PECI 1.1, 2.0, and 3.0. The AST2600 and AST1030 support
PECI 4.0, which includes more read/write buffer registers from 0x80 to
0xFC to support 64-byte mode.

This patch doesn't attempt to handle that, or to create a different
version of the controller for the different generations, since it's only
implementing functionality that is common to all generations.

The basic sequence of events is that the firmware will read and write to
various registers and then trigger a command by setting the FIRE bit in
the command register (similar to the I2C controller).

Then the firmware waits for an interrupt from the PECI controller,
expecting the interrupt status register to be filled in with info on
what happened. If the command was transmitted and received successfully,
then response codes from the host CPU will be found in the data buffer
registers.

Signed-off-by: Peter Delevoryas <pdel@fb.com>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
Message-Id: <20220630045133.32251-12-me@pjd.dev>
[ clg: s/sysbus_mmio_map/aspeed_mmio_map/ ]
Signed-off-by: Cédric Le Goater <clg@kaod.org>
2022-06-30 09:21:14 +02:00

640 lines
23 KiB
C

/*
* ASPEED SoC 2600 family
*
* Copyright (c) 2016-2019, IBM Corporation.
*
* This code is licensed under the GPL version 2 or later. See
* the COPYING file in the top-level directory.
*/
#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"
#define ASPEED_SOC_IOMEM_SIZE 0x00200000
#define ASPEED_SOC_DPMCU_SIZE 0x00040000
static const hwaddr aspeed_soc_ast2600_memmap[] = {
[ASPEED_DEV_SRAM] = 0x10000000,
[ASPEED_DEV_DPMCU] = 0x18000000,
/* 0x16000000 0x17FFFFFF : AHB BUS do LPC Bus bridge */
[ASPEED_DEV_IOMEM] = 0x1E600000,
[ASPEED_DEV_PWM] = 0x1E610000,
[ASPEED_DEV_FMC] = 0x1E620000,
[ASPEED_DEV_SPI1] = 0x1E630000,
[ASPEED_DEV_SPI2] = 0x1E631000,
[ASPEED_DEV_EHCI1] = 0x1E6A1000,
[ASPEED_DEV_EHCI2] = 0x1E6A3000,
[ASPEED_DEV_MII1] = 0x1E650000,
[ASPEED_DEV_MII2] = 0x1E650008,
[ASPEED_DEV_MII3] = 0x1E650010,
[ASPEED_DEV_MII4] = 0x1E650018,
[ASPEED_DEV_ETH1] = 0x1E660000,
[ASPEED_DEV_ETH3] = 0x1E670000,
[ASPEED_DEV_ETH2] = 0x1E680000,
[ASPEED_DEV_ETH4] = 0x1E690000,
[ASPEED_DEV_VIC] = 0x1E6C0000,
[ASPEED_DEV_HACE] = 0x1E6D0000,
[ASPEED_DEV_SDMC] = 0x1E6E0000,
[ASPEED_DEV_SCU] = 0x1E6E2000,
[ASPEED_DEV_XDMA] = 0x1E6E7000,
[ASPEED_DEV_ADC] = 0x1E6E9000,
[ASPEED_DEV_DP] = 0x1E6EB000,
[ASPEED_DEV_SBC] = 0x1E6F2000,
[ASPEED_DEV_EMMC_BC] = 0x1E6f5000,
[ASPEED_DEV_VIDEO] = 0x1E700000,
[ASPEED_DEV_SDHCI] = 0x1E740000,
[ASPEED_DEV_EMMC] = 0x1E750000,
[ASPEED_DEV_GPIO] = 0x1E780000,
[ASPEED_DEV_GPIO_1_8V] = 0x1E780800,
[ASPEED_DEV_RTC] = 0x1E781000,
[ASPEED_DEV_TIMER1] = 0x1E782000,
[ASPEED_DEV_WDT] = 0x1E785000,
[ASPEED_DEV_LPC] = 0x1E789000,
[ASPEED_DEV_IBT] = 0x1E789140,
[ASPEED_DEV_I2C] = 0x1E78A000,
[ASPEED_DEV_PECI] = 0x1E78B000,
[ASPEED_DEV_UART1] = 0x1E783000,
[ASPEED_DEV_UART2] = 0x1E78D000,
[ASPEED_DEV_UART3] = 0x1E78E000,
[ASPEED_DEV_UART4] = 0x1E78F000,
[ASPEED_DEV_UART5] = 0x1E784000,
[ASPEED_DEV_UART6] = 0x1E790000,
[ASPEED_DEV_UART7] = 0x1E790100,
[ASPEED_DEV_UART8] = 0x1E790200,
[ASPEED_DEV_UART9] = 0x1E790300,
[ASPEED_DEV_UART10] = 0x1E790400,
[ASPEED_DEV_UART11] = 0x1E790500,
[ASPEED_DEV_UART12] = 0x1E790600,
[ASPEED_DEV_UART13] = 0x1E790700,
[ASPEED_DEV_VUART] = 0x1E787000,
[ASPEED_DEV_I3C] = 0x1E7A0000,
[ASPEED_DEV_SDRAM] = 0x80000000,
};
#define ASPEED_A7MPCORE_ADDR 0x40460000
#define AST2600_MAX_IRQ 197
/* Shared Peripheral Interrupt values below are offset by -32 from datasheet */
static const int aspeed_soc_ast2600_irqmap[] = {
[ASPEED_DEV_UART1] = 47,
[ASPEED_DEV_UART2] = 48,
[ASPEED_DEV_UART3] = 49,
[ASPEED_DEV_UART4] = 50,
[ASPEED_DEV_UART5] = 8,
[ASPEED_DEV_UART6] = 57,
[ASPEED_DEV_UART7] = 58,
[ASPEED_DEV_UART8] = 59,
[ASPEED_DEV_UART9] = 60,
[ASPEED_DEV_UART10] = 61,
[ASPEED_DEV_UART11] = 62,
[ASPEED_DEV_UART12] = 63,
[ASPEED_DEV_UART13] = 64,
[ASPEED_DEV_VUART] = 8,
[ASPEED_DEV_FMC] = 39,
[ASPEED_DEV_SDMC] = 0,
[ASPEED_DEV_SCU] = 12,
[ASPEED_DEV_ADC] = 78,
[ASPEED_DEV_XDMA] = 6,
[ASPEED_DEV_SDHCI] = 43,
[ASPEED_DEV_EHCI1] = 5,
[ASPEED_DEV_EHCI2] = 9,
[ASPEED_DEV_EMMC] = 15,
[ASPEED_DEV_GPIO] = 40,
[ASPEED_DEV_GPIO_1_8V] = 11,
[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] = 24,
[ASPEED_DEV_PWM] = 44,
[ASPEED_DEV_LPC] = 35,
[ASPEED_DEV_IBT] = 143,
[ASPEED_DEV_I2C] = 110, /* 110 -> 125 */
[ASPEED_DEV_PECI] = 38,
[ASPEED_DEV_ETH1] = 2,
[ASPEED_DEV_ETH2] = 3,
[ASPEED_DEV_HACE] = 4,
[ASPEED_DEV_ETH3] = 32,
[ASPEED_DEV_ETH4] = 33,
[ASPEED_DEV_KCS] = 138, /* 138 -> 142 */
[ASPEED_DEV_DP] = 62,
[ASPEED_DEV_I3C] = 102, /* 102 -> 107 */
};
static qemu_irq aspeed_soc_ast2600_get_irq(AspeedSoCState *s, int dev)
{
AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
return qdev_get_gpio_in(DEVICE(&s->a7mpcore), sc->irqmap[dev]);
}
static void aspeed_soc_ast2600_init(Object *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[*]", &s->cpu[i], sc->cpu_type);
}
snprintf(typename, sizeof(typename), "aspeed.scu-%s", socname);
object_initialize_child(obj, "scu", &s->scu, typename);
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, "a7mpcore", &s->a7mpcore,
TYPE_A15MPCORE_PRIV);
object_initialize_child(obj, "rtc", &s->rtc, TYPE_ASPEED_RTC);
snprintf(typename, sizeof(typename), "aspeed.timer-%s", socname);
object_initialize_child(obj, "timerctrl", &s->timerctrl, typename);
snprintf(typename, sizeof(typename), "aspeed.adc-%s", socname);
object_initialize_child(obj, "adc", &s->adc, typename);
snprintf(typename, sizeof(typename), "aspeed.i2c-%s", socname);
object_initialize_child(obj, "i2c", &s->i2c, typename);
object_initialize_child(obj, "peci", &s->peci, TYPE_ASPEED_PECI);
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 + 1, socname);
object_initialize_child(obj, "spi[*]", &s->spi[i], typename);
}
for (i = 0; i < sc->ehcis_num; i++) {
object_initialize_child(obj, "ehci[*]", &s->ehci[i],
TYPE_PLATFORM_EHCI);
}
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);
}
snprintf(typename, sizeof(typename), TYPE_ASPEED_XDMA "-%s", socname);
object_initialize_child(obj, "xdma", &s->xdma, typename);
snprintf(typename, sizeof(typename), "aspeed.gpio-%s", socname);
object_initialize_child(obj, "gpio", &s->gpio, typename);
snprintf(typename, sizeof(typename), "aspeed.gpio-%s-1_8v", socname);
object_initialize_child(obj, "gpio_1_8v", &s->gpio_1_8v, typename);
object_initialize_child(obj, "sd-controller", &s->sdhci,
TYPE_ASPEED_SDHCI);
object_property_set_int(OBJECT(&s->sdhci), "num-slots", 2, &error_abort);
/* Init sd card slot class here so that they're under the correct parent */
for (i = 0; i < ASPEED_SDHCI_NUM_SLOTS; ++i) {
object_initialize_child(obj, "sd-controller.sdhci[*]",
&s->sdhci.slots[i], TYPE_SYSBUS_SDHCI);
}
object_initialize_child(obj, "emmc-controller", &s->emmc,
TYPE_ASPEED_SDHCI);
object_property_set_int(OBJECT(&s->emmc), "num-slots", 1, &error_abort);
object_initialize_child(obj, "emmc-controller.sdhci", &s->emmc.slots[0],
TYPE_SYSBUS_SDHCI);
object_initialize_child(obj, "lpc", &s->lpc, TYPE_ASPEED_LPC);
snprintf(typename, sizeof(typename), "aspeed.hace-%s", socname);
object_initialize_child(obj, "hace", &s->hace, typename);
object_initialize_child(obj, "i3c", &s->i3c, TYPE_ASPEED_I3C);
object_initialize_child(obj, "sbc", &s->sbc, TYPE_ASPEED_SBC);
object_initialize_child(obj, "iomem", &s->iomem, TYPE_UNIMPLEMENTED_DEVICE);
object_initialize_child(obj, "video", &s->video, TYPE_UNIMPLEMENTED_DEVICE);
object_initialize_child(obj, "dpmcu", &s->dpmcu, TYPE_UNIMPLEMENTED_DEVICE);
object_initialize_child(obj, "emmc-boot-controller",
&s->emmc_boot_controller,
TYPE_UNIMPLEMENTED_DEVICE);
}
/*
* ASPEED ast2600 has 0xf as cluster ID
*
* https://developer.arm.com/documentation/ddi0388/e/the-system-control-coprocessors/summary-of-system-control-coprocessor-registers/multiprocessor-affinity-register
*/
static uint64_t aspeed_calc_affinity(int cpu)
{
return (0xf << ARM_AFF1_SHIFT) | cpu;
}
static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
{
int i;
AspeedSoCState *s = ASPEED_SOC(dev);
AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
Error *err = NULL;
qemu_irq irq;
/* IO space */
aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->iomem), "aspeed.io",
sc->memmap[ASPEED_DEV_IOMEM],
ASPEED_SOC_IOMEM_SIZE);
/* Video engine stub */
aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->video), "aspeed.video",
sc->memmap[ASPEED_DEV_VIDEO], 0x1000);
/* eMMC Boot Controller stub */
aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->emmc_boot_controller),
"aspeed.emmc-boot-controller",
sc->memmap[ASPEED_DEV_EMMC_BC], 0x1000);
/* CPU */
for (i = 0; i < sc->num_cpus; i++) {
if (sc->num_cpus > 1) {
object_property_set_int(OBJECT(&s->cpu[i]), "reset-cbar",
ASPEED_A7MPCORE_ADDR, &error_abort);
}
object_property_set_int(OBJECT(&s->cpu[i]), "mp-affinity",
aspeed_calc_affinity(i), &error_abort);
object_property_set_int(OBJECT(&s->cpu[i]), "cntfrq", 1125000000,
&error_abort);
object_property_set_link(OBJECT(&s->cpu[i]), "memory",
OBJECT(s->memory), &error_abort);
if (!qdev_realize(DEVICE(&s->cpu[i]), NULL, errp)) {
return;
}
}
/* A7MPCORE */
object_property_set_int(OBJECT(&s->a7mpcore), "num-cpu", sc->num_cpus,
&error_abort);
object_property_set_int(OBJECT(&s->a7mpcore), "num-irq",
ROUND_UP(AST2600_MAX_IRQ + GIC_INTERNAL, 32),
&error_abort);
sysbus_realize(SYS_BUS_DEVICE(&s->a7mpcore), &error_abort);
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->a7mpcore), 0, ASPEED_A7MPCORE_ADDR);
for (i = 0; i < sc->num_cpus; i++) {
SysBusDevice *sbd = SYS_BUS_DEVICE(&s->a7mpcore);
DeviceState *d = DEVICE(&s->cpu[i]);
irq = qdev_get_gpio_in(d, ARM_CPU_IRQ);
sysbus_connect_irq(sbd, i, irq);
irq = qdev_get_gpio_in(d, ARM_CPU_FIQ);
sysbus_connect_irq(sbd, i + sc->num_cpus, irq);
irq = qdev_get_gpio_in(d, ARM_CPU_VIRQ);
sysbus_connect_irq(sbd, i + 2 * sc->num_cpus, irq);
irq = qdev_get_gpio_in(d, ARM_CPU_VFIQ);
sysbus_connect_irq(sbd, i + 3 * sc->num_cpus, irq);
}
/* SRAM */
memory_region_init_ram(&s->sram, OBJECT(dev), "aspeed.sram",
sc->sram_size, &err);
if (err) {
error_propagate(errp, err);
return;
}
memory_region_add_subregion(s->memory,
sc->memmap[ASPEED_DEV_SRAM], &s->sram);
/* DPMCU */
aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->dpmcu), "aspeed.dpmcu",
sc->memmap[ASPEED_DEV_DPMCU],
ASPEED_SOC_DPMCU_SIZE);
/* 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]);
/* RTC */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->rtc), errp)) {
return;
}
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->rtc), 0, sc->memmap[ASPEED_DEV_RTC]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->rtc), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_RTC));
/* Timer */
object_property_set_link(OBJECT(&s->timerctrl), "scu", OBJECT(&s->scu),
&error_abort);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->timerctrl), errp)) {
return;
}
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->timerctrl), 0,
sc->memmap[ASPEED_DEV_TIMER1]);
for (i = 0; i < ASPEED_TIMER_NR_TIMERS; i++) {
qemu_irq irq = aspeed_soc_get_irq(s, ASPEED_DEV_TIMER1 + i);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->timerctrl), i, irq);
}
/* ADC */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->adc), errp)) {
return;
}
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->adc), 0, sc->memmap[ASPEED_DEV_ADC]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->adc), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_ADC));
/* UART */
aspeed_soc_uart_init(s);
/* I2C */
object_property_set_link(OBJECT(&s->i2c), "dram", OBJECT(s->dram_mr),
&error_abort);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c), errp)) {
return;
}
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->i2c), 0, sc->memmap[ASPEED_DEV_I2C]);
for (i = 0; i < ASPEED_I2C_GET_CLASS(&s->i2c)->num_busses; i++) {
qemu_irq irq = qdev_get_gpio_in(DEVICE(&s->a7mpcore),
sc->irqmap[ASPEED_DEV_I2C] + i);
/* The AST2600 I2C controller has one IRQ per bus. */
sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c.busses[i]), 0, irq);
}
/* PECI */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->peci), errp)) {
return;
}
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->peci), 0,
sc->memmap[ASPEED_DEV_PECI]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->peci), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_PECI));
/* FMC, The number of CS is set at the board level */
object_property_set_link(OBJECT(&s->fmc), "dram", OBJECT(s->dram_mr),
&error_abort);
if (!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));
/* 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_SPI1 + i]);
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->spi[i]), 1,
ASPEED_SMC_GET_CLASS(&s->spi[i])->flash_window_base);
}
/* EHCI */
for (i = 0; i < sc->ehcis_num; i++) {
if (!sysbus_realize(SYS_BUS_DEVICE(&s->ehci[i]), errp)) {
return;
}
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->ehci[i]), 0,
sc->memmap[ASPEED_DEV_EHCI1 + i]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->ehci[i]), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_EHCI1 + i));
}
/* SDMC - SDRAM Memory Controller */
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]);
/* Watch dog */
for (i = 0; i < sc->wdts_num; i++) {
AspeedWDTClass *awc = ASPEED_WDT_GET_CLASS(&s->wdt[i]);
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,
sc->memmap[ASPEED_DEV_WDT] + i * awc->offset);
}
/* RAM */
if (!aspeed_soc_dram_init(s, errp)) {
return;
}
/* Net */
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]);
}
/* XDMA */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->xdma), errp)) {
return;
}
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->xdma), 0,
sc->memmap[ASPEED_DEV_XDMA]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->xdma), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_XDMA));
/* GPIO */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), errp)) {
return;
}
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->gpio), 0, sc->memmap[ASPEED_DEV_GPIO]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_GPIO));
if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio_1_8v), errp)) {
return;
}
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->gpio_1_8v), 0,
sc->memmap[ASPEED_DEV_GPIO_1_8V]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio_1_8v), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_GPIO_1_8V));
/* SDHCI */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->sdhci), errp)) {
return;
}
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sdhci), 0,
sc->memmap[ASPEED_DEV_SDHCI]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdhci), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_SDHCI));
/* eMMC */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->emmc), errp)) {
return;
}
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->emmc), 0,
sc->memmap[ASPEED_DEV_EMMC]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->emmc), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_EMMC));
/* LPC */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->lpc), errp)) {
return;
}
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->lpc), 0, sc->memmap[ASPEED_DEV_LPC]);
/* Connect the LPC IRQ to the GIC. It is otherwise unused. */
sysbus_connect_irq(SYS_BUS_DEVICE(&s->lpc), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_LPC));
/*
* On the AST2600 LPC subdevice IRQs are connected straight to the GIC.
*
* LPC subdevice IRQ sources are offset from 1 because the LPC model caters
* to the AST2400 and AST2500. SoCs before the AST2600 have one LPC IRQ
* shared across the subdevices, and the shared IRQ output to the VIC is at
* offset 0.
*/
sysbus_connect_irq(SYS_BUS_DEVICE(&s->lpc), 1 + aspeed_lpc_kcs_1,
qdev_get_gpio_in(DEVICE(&s->a7mpcore),
sc->irqmap[ASPEED_DEV_KCS] + aspeed_lpc_kcs_1));
sysbus_connect_irq(SYS_BUS_DEVICE(&s->lpc), 1 + aspeed_lpc_kcs_2,
qdev_get_gpio_in(DEVICE(&s->a7mpcore),
sc->irqmap[ASPEED_DEV_KCS] + aspeed_lpc_kcs_2));
sysbus_connect_irq(SYS_BUS_DEVICE(&s->lpc), 1 + aspeed_lpc_kcs_3,
qdev_get_gpio_in(DEVICE(&s->a7mpcore),
sc->irqmap[ASPEED_DEV_KCS] + aspeed_lpc_kcs_3));
sysbus_connect_irq(SYS_BUS_DEVICE(&s->lpc), 1 + aspeed_lpc_kcs_4,
qdev_get_gpio_in(DEVICE(&s->a7mpcore),
sc->irqmap[ASPEED_DEV_KCS] + aspeed_lpc_kcs_4));
/* HACE */
object_property_set_link(OBJECT(&s->hace), "dram", OBJECT(s->dram_mr),
&error_abort);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->hace), errp)) {
return;
}
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->hace), 0,
sc->memmap[ASPEED_DEV_HACE]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->hace), 0,
aspeed_soc_get_irq(s, ASPEED_DEV_HACE));
/* I3C */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->i3c), errp)) {
return;
}
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->i3c), 0, sc->memmap[ASPEED_DEV_I3C]);
for (i = 0; i < ASPEED_I3C_NR_DEVICES; i++) {
qemu_irq irq = qdev_get_gpio_in(DEVICE(&s->a7mpcore),
sc->irqmap[ASPEED_DEV_I3C] + i);
/* The AST2600 I3C controller has one IRQ per bus. */
sysbus_connect_irq(SYS_BUS_DEVICE(&s->i3c.devices[i]), 0, irq);
}
/* Secure Boot Controller */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->sbc), errp)) {
return;
}
aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sbc), 0, sc->memmap[ASPEED_DEV_SBC]);
}
static void aspeed_soc_ast2600_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
AspeedSoCClass *sc = ASPEED_SOC_CLASS(oc);
dc->realize = aspeed_soc_ast2600_realize;
sc->name = "ast2600-a3";
sc->cpu_type = ARM_CPU_TYPE_NAME("cortex-a7");
sc->silicon_rev = AST2600_A3_SILICON_REV;
sc->sram_size = 0x16400;
sc->spis_num = 2;
sc->ehcis_num = 2;
sc->wdts_num = 4;
sc->macs_num = 4;
sc->uarts_num = 13;
sc->irqmap = aspeed_soc_ast2600_irqmap;
sc->memmap = aspeed_soc_ast2600_memmap;
sc->num_cpus = 2;
sc->get_irq = aspeed_soc_ast2600_get_irq;
}
static const TypeInfo aspeed_soc_ast2600_type_info = {
.name = "ast2600-a3",
.parent = TYPE_ASPEED_SOC,
.instance_size = sizeof(AspeedSoCState),
.instance_init = aspeed_soc_ast2600_init,
.class_init = aspeed_soc_ast2600_class_init,
.class_size = sizeof(AspeedSoCClass),
};
static void aspeed_soc_register_types(void)
{
type_register_static(&aspeed_soc_ast2600_type_info);
};
type_init(aspeed_soc_register_types)