qemu-e2k/hw/arm/aspeed_soc.c

346 lines
13 KiB
C
Raw Normal View History

/*
* ASPEED SoC family
*
* Andrew Jeffery <andrew@aj.id.au>
* Jeremy Kerr <jk@ozlabs.org>
*
* Copyright 2016 IBM Corp.
*
* This code is licensed under the GPL version 2 or later. See
* the COPYING file in the top-level directory.
*/
#include "qemu/osdep.h"
2016-03-14 09:01:28 +01:00
#include "qapi/error.h"
#include "qemu-common.h"
#include "cpu.h"
#include "exec/address-spaces.h"
#include "hw/misc/unimp.h"
#include "hw/arm/aspeed_soc.h"
#include "hw/char/serial.h"
#include "qemu/log.h"
#include "hw/i2c/aspeed_i2c.h"
#include "net/net.h"
#define ASPEED_SOC_UART_5_BASE 0x00184000
#define ASPEED_SOC_IOMEM_SIZE 0x00200000
#define ASPEED_SOC_IOMEM_BASE 0x1E600000
#define ASPEED_SOC_FMC_BASE 0x1E620000
#define ASPEED_SOC_SPI_BASE 0x1E630000
#define ASPEED_SOC_SPI2_BASE 0x1E631000
#define ASPEED_SOC_VIC_BASE 0x1E6C0000
#define ASPEED_SOC_SDMC_BASE 0x1E6E0000
#define ASPEED_SOC_SCU_BASE 0x1E6E2000
#define ASPEED_SOC_SRAM_BASE 0x1E720000
#define ASPEED_SOC_TIMER_BASE 0x1E782000
#define ASPEED_SOC_WDT_BASE 0x1E785000
#define ASPEED_SOC_I2C_BASE 0x1E78A000
#define ASPEED_SOC_ETH1_BASE 0x1E660000
#define ASPEED_SOC_ETH2_BASE 0x1E680000
static const int uart_irqs[] = { 9, 32, 33, 34, 10 };
static const int timer_irqs[] = { 16, 17, 18, 35, 36, 37, 38, 39, };
#define AST2400_SDRAM_BASE 0x40000000
#define AST2500_SDRAM_BASE 0x80000000
static const hwaddr aspeed_soc_ast2400_spi_bases[] = { ASPEED_SOC_SPI_BASE };
static const char *aspeed_soc_ast2400_typenames[] = { "aspeed.smc.spi" };
static const hwaddr aspeed_soc_ast2500_spi_bases[] = { ASPEED_SOC_SPI_BASE,
ASPEED_SOC_SPI2_BASE};
static const char *aspeed_soc_ast2500_typenames[] = {
"aspeed.smc.ast2500-spi1", "aspeed.smc.ast2500-spi2" };
static const AspeedSoCInfo aspeed_socs[] = {
{
.name = "ast2400-a0",
arm: drop intermediate cpu_model -> cpu type parsing and use cpu type directly there are 2 use cases to deal with: 1: fixed CPU models per board/soc 2: boards with user configurable cpu_model and fallback to default cpu_model if user hasn't specified one explicitly For the 1st drop intermediate cpu_model parsing and use const cpu type directly, which replaces: typename = object_class_get_name( cpu_class_by_name(TYPE_ARM_CPU, cpu_model)) object_new(typename) with object_new(FOO_CPU_TYPE_NAME) or cpu_generic_init(BASE_CPU_TYPE, "my cpu model") with cpu_create(FOO_CPU_TYPE_NAME) as result 1st use case doesn't have to invoke not necessary translation and not needed code is removed. For the 2nd 1: set default cpu type with MachineClass::default_cpu_type and 2: use generic cpu_model parsing that done before machine_init() is run and: 2.1: drop custom cpu_model parsing where pattern is: typename = object_class_get_name( cpu_class_by_name(TYPE_ARM_CPU, cpu_model)) [parse_features(typename, cpu_model, &err) ] 2.2: or replace cpu_generic_init() which does what 2.1 does + create_cpu(typename) with just create_cpu(machine->cpu_type) as result cpu_name -> cpu_type translation is done using generic machine code one including parsing optional features if supported/present (removes a bunch of duplicated cpu_model parsing code) and default cpu type is defined in an uniform way within machine_class_init callbacks instead of adhoc places in boadr's machine_init code. Signed-off-by: Igor Mammedov <imammedo@redhat.com> Reviewed-by: Eduardo Habkost <ehabkost@redhat.com> Message-Id: <1505318697-77161-6-git-send-email-imammedo@redhat.com> Reviewed-by: Alistair Francis <alistair.francis@xilinx.com> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
2017-09-13 18:04:57 +02:00
.cpu_type = ARM_CPU_TYPE_NAME("arm926"),
.silicon_rev = AST2400_A0_SILICON_REV,
.sdram_base = AST2400_SDRAM_BASE,
.sram_size = 0x8000,
.spis_num = 1,
.spi_bases = aspeed_soc_ast2400_spi_bases,
.fmc_typename = "aspeed.smc.fmc",
.spi_typename = aspeed_soc_ast2400_typenames,
.wdts_num = 2,
}, {
.name = "ast2400-a1",
arm: drop intermediate cpu_model -> cpu type parsing and use cpu type directly there are 2 use cases to deal with: 1: fixed CPU models per board/soc 2: boards with user configurable cpu_model and fallback to default cpu_model if user hasn't specified one explicitly For the 1st drop intermediate cpu_model parsing and use const cpu type directly, which replaces: typename = object_class_get_name( cpu_class_by_name(TYPE_ARM_CPU, cpu_model)) object_new(typename) with object_new(FOO_CPU_TYPE_NAME) or cpu_generic_init(BASE_CPU_TYPE, "my cpu model") with cpu_create(FOO_CPU_TYPE_NAME) as result 1st use case doesn't have to invoke not necessary translation and not needed code is removed. For the 2nd 1: set default cpu type with MachineClass::default_cpu_type and 2: use generic cpu_model parsing that done before machine_init() is run and: 2.1: drop custom cpu_model parsing where pattern is: typename = object_class_get_name( cpu_class_by_name(TYPE_ARM_CPU, cpu_model)) [parse_features(typename, cpu_model, &err) ] 2.2: or replace cpu_generic_init() which does what 2.1 does + create_cpu(typename) with just create_cpu(machine->cpu_type) as result cpu_name -> cpu_type translation is done using generic machine code one including parsing optional features if supported/present (removes a bunch of duplicated cpu_model parsing code) and default cpu type is defined in an uniform way within machine_class_init callbacks instead of adhoc places in boadr's machine_init code. Signed-off-by: Igor Mammedov <imammedo@redhat.com> Reviewed-by: Eduardo Habkost <ehabkost@redhat.com> Message-Id: <1505318697-77161-6-git-send-email-imammedo@redhat.com> Reviewed-by: Alistair Francis <alistair.francis@xilinx.com> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
2017-09-13 18:04:57 +02:00
.cpu_type = ARM_CPU_TYPE_NAME("arm926"),
.silicon_rev = AST2400_A1_SILICON_REV,
.sdram_base = AST2400_SDRAM_BASE,
.sram_size = 0x8000,
.spis_num = 1,
.spi_bases = aspeed_soc_ast2400_spi_bases,
.fmc_typename = "aspeed.smc.fmc",
.spi_typename = aspeed_soc_ast2400_typenames,
.wdts_num = 2,
}, {
.name = "ast2400",
arm: drop intermediate cpu_model -> cpu type parsing and use cpu type directly there are 2 use cases to deal with: 1: fixed CPU models per board/soc 2: boards with user configurable cpu_model and fallback to default cpu_model if user hasn't specified one explicitly For the 1st drop intermediate cpu_model parsing and use const cpu type directly, which replaces: typename = object_class_get_name( cpu_class_by_name(TYPE_ARM_CPU, cpu_model)) object_new(typename) with object_new(FOO_CPU_TYPE_NAME) or cpu_generic_init(BASE_CPU_TYPE, "my cpu model") with cpu_create(FOO_CPU_TYPE_NAME) as result 1st use case doesn't have to invoke not necessary translation and not needed code is removed. For the 2nd 1: set default cpu type with MachineClass::default_cpu_type and 2: use generic cpu_model parsing that done before machine_init() is run and: 2.1: drop custom cpu_model parsing where pattern is: typename = object_class_get_name( cpu_class_by_name(TYPE_ARM_CPU, cpu_model)) [parse_features(typename, cpu_model, &err) ] 2.2: or replace cpu_generic_init() which does what 2.1 does + create_cpu(typename) with just create_cpu(machine->cpu_type) as result cpu_name -> cpu_type translation is done using generic machine code one including parsing optional features if supported/present (removes a bunch of duplicated cpu_model parsing code) and default cpu type is defined in an uniform way within machine_class_init callbacks instead of adhoc places in boadr's machine_init code. Signed-off-by: Igor Mammedov <imammedo@redhat.com> Reviewed-by: Eduardo Habkost <ehabkost@redhat.com> Message-Id: <1505318697-77161-6-git-send-email-imammedo@redhat.com> Reviewed-by: Alistair Francis <alistair.francis@xilinx.com> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
2017-09-13 18:04:57 +02:00
.cpu_type = ARM_CPU_TYPE_NAME("arm926"),
.silicon_rev = AST2400_A0_SILICON_REV,
.sdram_base = AST2400_SDRAM_BASE,
.sram_size = 0x8000,
.spis_num = 1,
.spi_bases = aspeed_soc_ast2400_spi_bases,
.fmc_typename = "aspeed.smc.fmc",
.spi_typename = aspeed_soc_ast2400_typenames,
.wdts_num = 2,
}, {
.name = "ast2500-a1",
arm: drop intermediate cpu_model -> cpu type parsing and use cpu type directly there are 2 use cases to deal with: 1: fixed CPU models per board/soc 2: boards with user configurable cpu_model and fallback to default cpu_model if user hasn't specified one explicitly For the 1st drop intermediate cpu_model parsing and use const cpu type directly, which replaces: typename = object_class_get_name( cpu_class_by_name(TYPE_ARM_CPU, cpu_model)) object_new(typename) with object_new(FOO_CPU_TYPE_NAME) or cpu_generic_init(BASE_CPU_TYPE, "my cpu model") with cpu_create(FOO_CPU_TYPE_NAME) as result 1st use case doesn't have to invoke not necessary translation and not needed code is removed. For the 2nd 1: set default cpu type with MachineClass::default_cpu_type and 2: use generic cpu_model parsing that done before machine_init() is run and: 2.1: drop custom cpu_model parsing where pattern is: typename = object_class_get_name( cpu_class_by_name(TYPE_ARM_CPU, cpu_model)) [parse_features(typename, cpu_model, &err) ] 2.2: or replace cpu_generic_init() which does what 2.1 does + create_cpu(typename) with just create_cpu(machine->cpu_type) as result cpu_name -> cpu_type translation is done using generic machine code one including parsing optional features if supported/present (removes a bunch of duplicated cpu_model parsing code) and default cpu type is defined in an uniform way within machine_class_init callbacks instead of adhoc places in boadr's machine_init code. Signed-off-by: Igor Mammedov <imammedo@redhat.com> Reviewed-by: Eduardo Habkost <ehabkost@redhat.com> Message-Id: <1505318697-77161-6-git-send-email-imammedo@redhat.com> Reviewed-by: Alistair Francis <alistair.francis@xilinx.com> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
2017-09-13 18:04:57 +02:00
.cpu_type = ARM_CPU_TYPE_NAME("arm1176"),
.silicon_rev = AST2500_A1_SILICON_REV,
.sdram_base = AST2500_SDRAM_BASE,
.sram_size = 0x9000,
.spis_num = 2,
.spi_bases = aspeed_soc_ast2500_spi_bases,
.fmc_typename = "aspeed.smc.ast2500-fmc",
.spi_typename = aspeed_soc_ast2500_typenames,
.wdts_num = 3,
},
};
static void aspeed_soc_init(Object *obj)
{
AspeedSoCState *s = ASPEED_SOC(obj);
AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
int i;
arm: drop intermediate cpu_model -> cpu type parsing and use cpu type directly there are 2 use cases to deal with: 1: fixed CPU models per board/soc 2: boards with user configurable cpu_model and fallback to default cpu_model if user hasn't specified one explicitly For the 1st drop intermediate cpu_model parsing and use const cpu type directly, which replaces: typename = object_class_get_name( cpu_class_by_name(TYPE_ARM_CPU, cpu_model)) object_new(typename) with object_new(FOO_CPU_TYPE_NAME) or cpu_generic_init(BASE_CPU_TYPE, "my cpu model") with cpu_create(FOO_CPU_TYPE_NAME) as result 1st use case doesn't have to invoke not necessary translation and not needed code is removed. For the 2nd 1: set default cpu type with MachineClass::default_cpu_type and 2: use generic cpu_model parsing that done before machine_init() is run and: 2.1: drop custom cpu_model parsing where pattern is: typename = object_class_get_name( cpu_class_by_name(TYPE_ARM_CPU, cpu_model)) [parse_features(typename, cpu_model, &err) ] 2.2: or replace cpu_generic_init() which does what 2.1 does + create_cpu(typename) with just create_cpu(machine->cpu_type) as result cpu_name -> cpu_type translation is done using generic machine code one including parsing optional features if supported/present (removes a bunch of duplicated cpu_model parsing code) and default cpu type is defined in an uniform way within machine_class_init callbacks instead of adhoc places in boadr's machine_init code. Signed-off-by: Igor Mammedov <imammedo@redhat.com> Reviewed-by: Eduardo Habkost <ehabkost@redhat.com> Message-Id: <1505318697-77161-6-git-send-email-imammedo@redhat.com> Reviewed-by: Alistair Francis <alistair.francis@xilinx.com> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
2017-09-13 18:04:57 +02:00
object_initialize(&s->cpu, sizeof(s->cpu), sc->info->cpu_type);
object_property_add_child(obj, "cpu", OBJECT(&s->cpu), NULL);
object_initialize(&s->vic, sizeof(s->vic), TYPE_ASPEED_VIC);
object_property_add_child(obj, "vic", OBJECT(&s->vic), NULL);
qdev_set_parent_bus(DEVICE(&s->vic), sysbus_get_default());
object_initialize(&s->timerctrl, sizeof(s->timerctrl), TYPE_ASPEED_TIMER);
object_property_add_child(obj, "timerctrl", OBJECT(&s->timerctrl), NULL);
qdev_set_parent_bus(DEVICE(&s->timerctrl), sysbus_get_default());
object_initialize(&s->i2c, sizeof(s->i2c), TYPE_ASPEED_I2C);
object_property_add_child(obj, "i2c", OBJECT(&s->i2c), NULL);
qdev_set_parent_bus(DEVICE(&s->i2c), sysbus_get_default());
object_initialize(&s->scu, sizeof(s->scu), TYPE_ASPEED_SCU);
object_property_add_child(obj, "scu", OBJECT(&s->scu), NULL);
qdev_set_parent_bus(DEVICE(&s->scu), sysbus_get_default());
qdev_prop_set_uint32(DEVICE(&s->scu), "silicon-rev",
sc->info->silicon_rev);
object_property_add_alias(obj, "hw-strap1", OBJECT(&s->scu),
"hw-strap1", &error_abort);
object_property_add_alias(obj, "hw-strap2", OBJECT(&s->scu),
"hw-strap2", &error_abort);
object_property_add_alias(obj, "hw-prot-key", OBJECT(&s->scu),
"hw-prot-key", &error_abort);
object_initialize(&s->fmc, sizeof(s->fmc), sc->info->fmc_typename);
object_property_add_child(obj, "fmc", OBJECT(&s->fmc), NULL);
qdev_set_parent_bus(DEVICE(&s->fmc), sysbus_get_default());
object_property_add_alias(obj, "num-cs", OBJECT(&s->fmc), "num-cs",
&error_abort);
for (i = 0; i < sc->info->spis_num; i++) {
object_initialize(&s->spi[i], sizeof(s->spi[i]),
sc->info->spi_typename[i]);
object_property_add_child(obj, "spi[*]", OBJECT(&s->spi[i]), NULL);
qdev_set_parent_bus(DEVICE(&s->spi[i]), sysbus_get_default());
}
object_initialize(&s->sdmc, sizeof(s->sdmc), TYPE_ASPEED_SDMC);
object_property_add_child(obj, "sdmc", OBJECT(&s->sdmc), NULL);
qdev_set_parent_bus(DEVICE(&s->sdmc), sysbus_get_default());
qdev_prop_set_uint32(DEVICE(&s->sdmc), "silicon-rev",
sc->info->silicon_rev);
object_property_add_alias(obj, "ram-size", OBJECT(&s->sdmc),
"ram-size", &error_abort);
for (i = 0; i < sc->info->wdts_num; i++) {
object_initialize(&s->wdt[i], sizeof(s->wdt[i]), TYPE_ASPEED_WDT);
object_property_add_child(obj, "wdt[*]", OBJECT(&s->wdt[i]), NULL);
qdev_set_parent_bus(DEVICE(&s->wdt[i]), sysbus_get_default());
qdev_prop_set_uint32(DEVICE(&s->wdt[i]), "silicon-rev",
sc->info->silicon_rev);
}
object_initialize(&s->ftgmac100, sizeof(s->ftgmac100), TYPE_FTGMAC100);
object_property_add_child(obj, "ftgmac100", OBJECT(&s->ftgmac100), NULL);
qdev_set_parent_bus(DEVICE(&s->ftgmac100), sysbus_get_default());
}
static void aspeed_soc_realize(DeviceState *dev, Error **errp)
{
int i;
AspeedSoCState *s = ASPEED_SOC(dev);
AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
Error *err = NULL, *local_err = NULL;
/* IO space */
create_unimplemented_device("aspeed_soc.io",
ASPEED_SOC_IOMEM_BASE, ASPEED_SOC_IOMEM_SIZE);
/* CPU */
object_property_set_bool(OBJECT(&s->cpu), true, "realized", &err);
if (err) {
error_propagate(errp, err);
return;
}
/* SRAM */
memory_region_init_ram(&s->sram, OBJECT(dev), "aspeed.sram",
sc->info->sram_size, &err);
if (err) {
error_propagate(errp, err);
return;
}
memory_region_add_subregion(get_system_memory(), ASPEED_SOC_SRAM_BASE,
&s->sram);
/* VIC */
object_property_set_bool(OBJECT(&s->vic), true, "realized", &err);
if (err) {
error_propagate(errp, err);
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->vic), 0, ASPEED_SOC_VIC_BASE);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->vic), 0,
qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_IRQ));
sysbus_connect_irq(SYS_BUS_DEVICE(&s->vic), 1,
qdev_get_gpio_in(DEVICE(&s->cpu), ARM_CPU_FIQ));
/* Timer */
object_property_set_bool(OBJECT(&s->timerctrl), true, "realized", &err);
if (err) {
error_propagate(errp, err);
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->timerctrl), 0, ASPEED_SOC_TIMER_BASE);
for (i = 0; i < ARRAY_SIZE(timer_irqs); i++) {
qemu_irq irq = qdev_get_gpio_in(DEVICE(&s->vic), timer_irqs[i]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->timerctrl), i, irq);
}
/* SCU */
object_property_set_bool(OBJECT(&s->scu), true, "realized", &err);
if (err) {
error_propagate(errp, err);
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->scu), 0, ASPEED_SOC_SCU_BASE);
/* UART - attach an 8250 to the IO space as our UART5 */
if (serial_hd(0)) {
qemu_irq uart5 = qdev_get_gpio_in(DEVICE(&s->vic), uart_irqs[4]);
serial_mm_init(get_system_memory(),
ASPEED_SOC_IOMEM_BASE + ASPEED_SOC_UART_5_BASE, 2,
uart5, 38400, serial_hd(0), DEVICE_LITTLE_ENDIAN);
}
/* I2C */
object_property_set_bool(OBJECT(&s->i2c), true, "realized", &err);
if (err) {
error_propagate(errp, err);
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c), 0, ASPEED_SOC_I2C_BASE);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c), 0,
qdev_get_gpio_in(DEVICE(&s->vic), 12));
/* FMC, The number of CS is set at the board level */
object_property_set_bool(OBJECT(&s->fmc), true, "realized", &err);
if (err) {
error_propagate(errp, err);
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 0, ASPEED_SOC_FMC_BASE);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 1,
s->fmc.ctrl->flash_window_base);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->fmc), 0,
qdev_get_gpio_in(DEVICE(&s->vic), 19));
/* SPI */
for (i = 0; i < sc->info->spis_num; i++) {
object_property_set_int(OBJECT(&s->spi[i]), 1, "num-cs", &err);
object_property_set_bool(OBJECT(&s->spi[i]), true, "realized",
&local_err);
error_propagate(&err, local_err);
if (err) {
error_propagate(errp, err);
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0, sc->info->spi_bases[i]);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 1,
s->spi[i].ctrl->flash_window_base);
}
/* SDMC - SDRAM Memory Controller */
object_property_set_bool(OBJECT(&s->sdmc), true, "realized", &err);
if (err) {
error_propagate(errp, err);
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdmc), 0, ASPEED_SOC_SDMC_BASE);
/* Watch dog */
for (i = 0; i < sc->info->wdts_num; i++) {
object_property_set_bool(OBJECT(&s->wdt[i]), true, "realized", &err);
if (err) {
error_propagate(errp, err);
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[i]), 0,
ASPEED_SOC_WDT_BASE + i * 0x20);
}
/* Net */
qdev_set_nic_properties(DEVICE(&s->ftgmac100), &nd_table[0]);
object_property_set_bool(OBJECT(&s->ftgmac100), true, "aspeed", &err);
object_property_set_bool(OBJECT(&s->ftgmac100), true, "realized",
&local_err);
error_propagate(&err, local_err);
if (err) {
error_propagate(errp, err);
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->ftgmac100), 0, ASPEED_SOC_ETH1_BASE);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->ftgmac100), 0,
qdev_get_gpio_in(DEVICE(&s->vic), 2));
}
static void aspeed_soc_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
AspeedSoCClass *sc = ASPEED_SOC_CLASS(oc);
sc->info = (AspeedSoCInfo *) data;
dc->realize = aspeed_soc_realize;
/* Reason: Uses serial_hds and nd_table in realize() directly */
dc->user_creatable = false;
}
static const TypeInfo aspeed_soc_type_info = {
.name = TYPE_ASPEED_SOC,
.parent = TYPE_DEVICE,
.instance_init = aspeed_soc_init,
.instance_size = sizeof(AspeedSoCState),
.class_size = sizeof(AspeedSoCClass),
.abstract = true,
};
static void aspeed_soc_register_types(void)
{
int i;
type_register_static(&aspeed_soc_type_info);
for (i = 0; i < ARRAY_SIZE(aspeed_socs); ++i) {
TypeInfo ti = {
.name = aspeed_socs[i].name,
.parent = TYPE_ASPEED_SOC,
.class_init = aspeed_soc_class_init,
.class_data = (void *) &aspeed_socs[i],
};
type_register(&ti);
}
}
type_init(aspeed_soc_register_types)