Upstream: https://gitlab.com/qemu-project/qemu.git Upstream-Commit: d2e570cc0f97b936902a5b1b86b73c0f5998b475
274 lines
9.4 KiB
C
274 lines
9.4 KiB
C
/*
|
|
* ASPEED AST1700 IO Expander
|
|
*
|
|
* Copyright (C) 2025 ASPEED Technology Inc.
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
*/
|
|
|
|
#include "qemu/osdep.h"
|
|
#include "hw/core/boards.h"
|
|
#include "qom/object.h"
|
|
#include "qapi/error.h"
|
|
#include "hw/core/qdev-properties.h"
|
|
#include "hw/arm/aspeed_ast1700.h"
|
|
|
|
#define AST2700_SOC_LTPI_SIZE 0x01000000
|
|
#define AST1700_SOC_SRAM_SIZE 0x00040000
|
|
#define AST1700_SOC_I3C_SIZE 0x00010000
|
|
|
|
enum {
|
|
ASPEED_AST1700_DEV_SPI0,
|
|
ASPEED_AST1700_DEV_PWM,
|
|
ASPEED_AST1700_DEV_SRAM,
|
|
ASPEED_AST1700_DEV_ADC,
|
|
ASPEED_AST1700_DEV_SCU,
|
|
ASPEED_AST1700_DEV_GPIO,
|
|
ASPEED_AST1700_DEV_SGPIOM0,
|
|
ASPEED_AST1700_DEV_SGPIOM1,
|
|
ASPEED_AST1700_DEV_I2C,
|
|
ASPEED_AST1700_DEV_I3C,
|
|
ASPEED_AST1700_DEV_UART12,
|
|
ASPEED_AST1700_DEV_LTPI_CTRL,
|
|
ASPEED_AST1700_DEV_WDT,
|
|
ASPEED_AST1700_DEV_SPI0_MEM,
|
|
};
|
|
|
|
static const hwaddr aspeed_ast1700_io_memmap[] = {
|
|
[ASPEED_AST1700_DEV_SPI0] = 0x00030000,
|
|
[ASPEED_AST1700_DEV_PWM] = 0x000C0000,
|
|
[ASPEED_AST1700_DEV_SRAM] = 0x00BC0000,
|
|
[ASPEED_AST1700_DEV_ADC] = 0x00C00000,
|
|
[ASPEED_AST1700_DEV_SCU] = 0x00C02000,
|
|
[ASPEED_AST1700_DEV_GPIO] = 0x00C0B000,
|
|
[ASPEED_AST1700_DEV_SGPIOM0] = 0x00C0C000,
|
|
[ASPEED_AST1700_DEV_SGPIOM1] = 0x00C0D000,
|
|
[ASPEED_AST1700_DEV_I2C] = 0x00C0F000,
|
|
[ASPEED_AST1700_DEV_I3C] = 0x00C20000,
|
|
[ASPEED_AST1700_DEV_UART12] = 0x00C33B00,
|
|
[ASPEED_AST1700_DEV_LTPI_CTRL] = 0x00C34000,
|
|
[ASPEED_AST1700_DEV_WDT] = 0x00C37000,
|
|
[ASPEED_AST1700_DEV_SPI0_MEM] = 0x04000000,
|
|
};
|
|
|
|
static void aspeed_ast1700_realize(DeviceState *dev, Error **errp)
|
|
{
|
|
AspeedAST1700SoCState *s = ASPEED_AST1700(dev);
|
|
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
|
char dev_name[32];
|
|
|
|
if (!s->dram_mr) {
|
|
error_setg(errp, TYPE_ASPEED_AST1700 ": 'dram' link not set");
|
|
return;
|
|
}
|
|
|
|
/* Occupy memory space for all controllers in AST1700 */
|
|
memory_region_init(&s->iomem, OBJECT(s), TYPE_ASPEED_AST1700,
|
|
AST2700_SOC_LTPI_SIZE);
|
|
sysbus_init_mmio(sbd, &s->iomem);
|
|
|
|
/* SRAM */
|
|
snprintf(dev_name, sizeof(dev_name), "aspeed.ioexp-sram.%d", s->board_idx);
|
|
memory_region_init_ram(&s->sram, OBJECT(s), dev_name,
|
|
AST1700_SOC_SRAM_SIZE, errp);
|
|
memory_region_add_subregion(&s->iomem,
|
|
aspeed_ast1700_io_memmap[ASPEED_AST1700_DEV_SRAM],
|
|
&s->sram);
|
|
|
|
/* UART */
|
|
qdev_prop_set_uint8(DEVICE(&s->uart), "regshift", 2);
|
|
qdev_prop_set_uint32(DEVICE(&s->uart), "baudbase", 38400);
|
|
qdev_prop_set_uint8(DEVICE(&s->uart), "endianness", DEVICE_LITTLE_ENDIAN);
|
|
if (!sysbus_realize(SYS_BUS_DEVICE(&s->uart), errp)) {
|
|
return;
|
|
}
|
|
memory_region_add_subregion(&s->iomem,
|
|
aspeed_ast1700_io_memmap[ASPEED_AST1700_DEV_UART12],
|
|
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->uart), 0));
|
|
|
|
/* SPI */
|
|
object_property_set_link(OBJECT(&s->spi), "dram",
|
|
OBJECT(s->dram_mr), errp);
|
|
if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi), errp)) {
|
|
return;
|
|
}
|
|
memory_region_add_subregion(&s->iomem,
|
|
aspeed_ast1700_io_memmap[ASPEED_AST1700_DEV_SPI0],
|
|
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->spi), 0));
|
|
|
|
memory_region_add_subregion(&s->iomem,
|
|
aspeed_ast1700_io_memmap[ASPEED_AST1700_DEV_SPI0_MEM],
|
|
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->spi), 1));
|
|
|
|
/* ADC */
|
|
if (!sysbus_realize(SYS_BUS_DEVICE(&s->adc), errp)) {
|
|
return;
|
|
}
|
|
memory_region_add_subregion(&s->iomem,
|
|
aspeed_ast1700_io_memmap[ASPEED_AST1700_DEV_ADC],
|
|
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->adc), 0));
|
|
|
|
/* SCU */
|
|
qdev_prop_set_uint32(DEVICE(&s->scu), "silicon-rev",
|
|
s->silicon_rev);
|
|
if (!sysbus_realize(SYS_BUS_DEVICE(&s->scu), errp)) {
|
|
return;
|
|
}
|
|
memory_region_add_subregion(&s->iomem,
|
|
aspeed_ast1700_io_memmap[ASPEED_AST1700_DEV_SCU],
|
|
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->scu), 0));
|
|
|
|
/* GPIO */
|
|
if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), errp)) {
|
|
return;
|
|
}
|
|
memory_region_add_subregion(&s->iomem,
|
|
aspeed_ast1700_io_memmap[ASPEED_AST1700_DEV_GPIO],
|
|
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->gpio), 0));
|
|
|
|
/* I2C */
|
|
snprintf(dev_name, sizeof(dev_name), "ioexp%d", s->board_idx);
|
|
qdev_prop_set_string(DEVICE(&s->i2c), "bus-label", dev_name);
|
|
|
|
object_property_set_link(OBJECT(&s->i2c), "dram",
|
|
OBJECT(s->dram_mr), errp);
|
|
if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c), errp)) {
|
|
return;
|
|
}
|
|
memory_region_add_subregion(&s->iomem,
|
|
aspeed_ast1700_io_memmap[ASPEED_AST1700_DEV_I2C],
|
|
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->i2c), 0));
|
|
|
|
/* PWM */
|
|
if (!sysbus_realize(SYS_BUS_DEVICE(&s->pwm), errp)) {
|
|
return;
|
|
}
|
|
memory_region_add_subregion(&s->iomem,
|
|
aspeed_ast1700_io_memmap[ASPEED_AST1700_DEV_PWM],
|
|
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->pwm), 0));
|
|
|
|
/* LTPI controller */
|
|
if (!sysbus_realize(SYS_BUS_DEVICE(&s->ltpi), errp)) {
|
|
return;
|
|
}
|
|
memory_region_add_subregion(&s->iomem,
|
|
aspeed_ast1700_io_memmap[ASPEED_AST1700_DEV_LTPI_CTRL],
|
|
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->ltpi), 0));
|
|
|
|
/* SGPIOM */
|
|
for (int i = 0; i < AST1700_SGPIO_NUM; i++) {
|
|
if (!sysbus_realize(SYS_BUS_DEVICE(&s->sgpiom[i]), errp)) {
|
|
return;
|
|
}
|
|
memory_region_add_subregion(&s->iomem,
|
|
aspeed_ast1700_io_memmap[ASPEED_AST1700_DEV_SGPIOM0 + i],
|
|
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->sgpiom[i]), 0));
|
|
}
|
|
|
|
/* WDT */
|
|
for (int i = 0; i < AST1700_WDT_NUM; i++) {
|
|
AspeedWDTClass *awc = ASPEED_WDT_GET_CLASS(&s->wdt[i]);
|
|
hwaddr wdt_offset = aspeed_ast1700_io_memmap[ASPEED_AST1700_DEV_WDT] +
|
|
i * awc->iosize;
|
|
|
|
object_property_set_link(OBJECT(&s->wdt[i]), "scu", OBJECT(&s->scu),
|
|
errp);
|
|
if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), errp)) {
|
|
return;
|
|
}
|
|
memory_region_add_subregion(&s->iomem,
|
|
wdt_offset,
|
|
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->wdt[i]), 0));
|
|
}
|
|
|
|
/* I3C */
|
|
qdev_prop_set_string(DEVICE(&s->i3c), "name", "ioexp-i3c");
|
|
qdev_prop_set_uint64(DEVICE(&s->i3c), "size", AST1700_SOC_I3C_SIZE);
|
|
sysbus_realize(SYS_BUS_DEVICE(&s->i3c), errp);
|
|
memory_region_add_subregion_overlap(&s->iomem,
|
|
aspeed_ast1700_io_memmap[ASPEED_AST1700_DEV_I3C],
|
|
sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->i3c), 0),
|
|
-1000);
|
|
}
|
|
|
|
static void aspeed_ast1700_instance_init(Object *obj)
|
|
{
|
|
AspeedAST1700SoCState *s = ASPEED_AST1700(obj);
|
|
|
|
/* UART */
|
|
object_initialize_child(obj, "uart", &s->uart,
|
|
TYPE_SERIAL_MM);
|
|
|
|
/* SPI */
|
|
object_initialize_child(obj, "ioexp-spi", &s->spi,
|
|
"aspeed.spi0-ast2700");
|
|
|
|
/* ADC */
|
|
object_initialize_child(obj, "ioexp-adc", &s->adc,
|
|
"aspeed.adc-ast2700");
|
|
|
|
/* SCU */
|
|
object_initialize_child(obj, "ioexp-scu", &s->scu,
|
|
TYPE_ASPEED_2700_SCU);
|
|
|
|
/* GPIO */
|
|
object_initialize_child(obj, "ioexp-gpio", &s->gpio,
|
|
"aspeed.gpio-ast2700");
|
|
|
|
/* I2C */
|
|
object_initialize_child(obj, "ioexp-i2c", &s->i2c,
|
|
"aspeed.i2c-ast2700");
|
|
|
|
/* PWM */
|
|
object_initialize_child(obj, "pwm", &s->pwm, TYPE_ASPEED_PWM);
|
|
|
|
/* LTPI controller */
|
|
object_initialize_child(obj, "ltpi-ctrl",
|
|
&s->ltpi, TYPE_ASPEED_LTPI);
|
|
|
|
/* SGPIOM */
|
|
for (int i = 0; i < AST1700_SGPIO_NUM; i++) {
|
|
object_initialize_child(obj, "ioexp-sgpiom[*]", &s->sgpiom[i],
|
|
"aspeed.sgpio-ast2700");
|
|
}
|
|
|
|
/* WDT */
|
|
for (int i = 0; i < AST1700_WDT_NUM; i++) {
|
|
object_initialize_child(obj, "ioexp-wdt[*]",
|
|
&s->wdt[i], "aspeed.wdt-ast2700");
|
|
}
|
|
|
|
/* I3C */
|
|
object_initialize_child(obj, "ioexp-i3c", &s->i3c,
|
|
TYPE_UNIMPLEMENTED_DEVICE);
|
|
|
|
return;
|
|
}
|
|
|
|
static const Property aspeed_ast1700_props[] = {
|
|
DEFINE_PROP_UINT8("board-idx", AspeedAST1700SoCState, board_idx, 0),
|
|
DEFINE_PROP_UINT32("silicon-rev", AspeedAST1700SoCState, silicon_rev, 0),
|
|
DEFINE_PROP_LINK("dram", AspeedAST1700SoCState, dram_mr,
|
|
TYPE_MEMORY_REGION, MemoryRegion *),
|
|
};
|
|
|
|
static void aspeed_ast1700_class_init(ObjectClass *klass, const void *data)
|
|
{
|
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
|
|
|
dc->realize = aspeed_ast1700_realize;
|
|
device_class_set_props(dc, aspeed_ast1700_props);
|
|
}
|
|
|
|
static const TypeInfo aspeed_ast1700_types[] = {
|
|
{
|
|
.name = TYPE_ASPEED_AST1700,
|
|
.parent = TYPE_SYS_BUS_DEVICE,
|
|
.instance_size = sizeof(AspeedAST1700SoCState),
|
|
.class_init = aspeed_ast1700_class_init,
|
|
.instance_init = aspeed_ast1700_instance_init,
|
|
}
|
|
};
|
|
|
|
DEFINE_TYPES(aspeed_ast1700_types)
|