diff --git a/hw/adc/aspeed_adc.c b/hw/adc/aspeed_adc.c new file mode 100644 index 0000000000..c5fcae29f6 --- /dev/null +++ b/hw/adc/aspeed_adc.c @@ -0,0 +1,427 @@ +/* + * Aspeed ADC + * + * Copyright 2017-2021 IBM Corp. + * + * Andrew Jeffery + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu/log.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "migration/vmstate.h" +#include "hw/adc/aspeed_adc.h" +#include "trace.h" + +#define ASPEED_ADC_MEMORY_REGION_SIZE 0x1000 +#define ASPEED_ADC_ENGINE_MEMORY_REGION_SIZE 0x100 +#define ASPEED_ADC_ENGINE_CH_EN_MASK 0xffff0000 +#define ASPEED_ADC_ENGINE_CH_EN(x) ((BIT(x)) << 16) +#define ASPEED_ADC_ENGINE_INIT BIT(8) +#define ASPEED_ADC_ENGINE_AUTO_COMP BIT(5) +#define ASPEED_ADC_ENGINE_COMP BIT(4) +#define ASPEED_ADC_ENGINE_MODE_MASK 0x0000000e +#define ASPEED_ADC_ENGINE_MODE_OFF (0b000 << 1) +#define ASPEED_ADC_ENGINE_MODE_STANDBY (0b001 << 1) +#define ASPEED_ADC_ENGINE_MODE_NORMAL (0b111 << 1) +#define ASPEED_ADC_ENGINE_EN BIT(0) +#define ASPEED_ADC_HYST_EN BIT(31) + +#define ASPEED_ADC_L_MASK ((1 << 10) - 1) +#define ASPEED_ADC_L(x) ((x) & ASPEED_ADC_L_MASK) +#define ASPEED_ADC_H(x) (((x) >> 16) & ASPEED_ADC_L_MASK) +#define ASPEED_ADC_LH_MASK (ASPEED_ADC_L_MASK << 16 | ASPEED_ADC_L_MASK) +#define LOWER_CHANNEL_MASK ((1 << 10) - 1) +#define LOWER_CHANNEL_DATA(x) ((x) & LOWER_CHANNEL_MASK) +#define UPPER_CHANNEL_DATA(x) (((x) >> 16) & LOWER_CHANNEL_MASK) + +#define TO_REG(addr) (addr >> 2) + +#define ENGINE_CONTROL TO_REG(0x00) +#define INTERRUPT_CONTROL TO_REG(0x04) +#define VGA_DETECT_CONTROL TO_REG(0x08) +#define CLOCK_CONTROL TO_REG(0x0C) +#define DATA_CHANNEL_1_AND_0 TO_REG(0x10) +#define DATA_CHANNEL_7_AND_6 TO_REG(0x1C) +#define DATA_CHANNEL_9_AND_8 TO_REG(0x20) +#define DATA_CHANNEL_15_AND_14 TO_REG(0x2C) +#define BOUNDS_CHANNEL_0 TO_REG(0x30) +#define BOUNDS_CHANNEL_7 TO_REG(0x4C) +#define BOUNDS_CHANNEL_8 TO_REG(0x50) +#define BOUNDS_CHANNEL_15 TO_REG(0x6C) +#define HYSTERESIS_CHANNEL_0 TO_REG(0x70) +#define HYSTERESIS_CHANNEL_7 TO_REG(0x8C) +#define HYSTERESIS_CHANNEL_8 TO_REG(0x90) +#define HYSTERESIS_CHANNEL_15 TO_REG(0xAC) +#define INTERRUPT_SOURCE TO_REG(0xC0) +#define COMPENSATING_AND_TRIMMING TO_REG(0xC4) + +static inline uint32_t update_channels(uint32_t current) +{ + return ((((current >> 16) & ASPEED_ADC_L_MASK) + 7) << 16) | + ((current + 5) & ASPEED_ADC_L_MASK); +} + +static bool breaks_threshold(AspeedADCEngineState *s, int reg) +{ + assert(reg >= DATA_CHANNEL_1_AND_0 && + reg < DATA_CHANNEL_1_AND_0 + s->nr_channels / 2); + + int a_bounds_reg = BOUNDS_CHANNEL_0 + (reg - DATA_CHANNEL_1_AND_0) * 2; + int b_bounds_reg = a_bounds_reg + 1; + uint32_t a_and_b = s->regs[reg]; + uint32_t a_bounds = s->regs[a_bounds_reg]; + uint32_t b_bounds = s->regs[b_bounds_reg]; + uint32_t a = ASPEED_ADC_L(a_and_b); + uint32_t b = ASPEED_ADC_H(a_and_b); + uint32_t a_lower = ASPEED_ADC_L(a_bounds); + uint32_t a_upper = ASPEED_ADC_H(a_bounds); + uint32_t b_lower = ASPEED_ADC_L(b_bounds); + uint32_t b_upper = ASPEED_ADC_H(b_bounds); + + return (a < a_lower || a > a_upper) || + (b < b_lower || b > b_upper); +} + +static uint32_t read_channel_sample(AspeedADCEngineState *s, int reg) +{ + assert(reg >= DATA_CHANNEL_1_AND_0 && + reg < DATA_CHANNEL_1_AND_0 + s->nr_channels / 2); + + /* Poor man's sampling */ + uint32_t value = s->regs[reg]; + s->regs[reg] = update_channels(s->regs[reg]); + + if (breaks_threshold(s, reg)) { + s->regs[INTERRUPT_CONTROL] |= BIT(reg - DATA_CHANNEL_1_AND_0); + qemu_irq_raise(s->irq); + } + + return value; +} + +static uint64_t aspeed_adc_engine_read(void *opaque, hwaddr addr, + unsigned int size) +{ + AspeedADCEngineState *s = ASPEED_ADC_ENGINE(opaque); + int reg = TO_REG(addr); + uint32_t value = 0; + + switch (reg) { + case BOUNDS_CHANNEL_8 ... BOUNDS_CHANNEL_15: + if (s->nr_channels <= 8) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: engine[%u]: " + "bounds register %u invalid, only 0...7 valid\n", + __func__, s->engine_id, reg - BOUNDS_CHANNEL_0); + break; + } + /* fallthrough */ + case HYSTERESIS_CHANNEL_8 ... HYSTERESIS_CHANNEL_15: + if (s->nr_channels <= 8) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: engine[%u]: " + "hysteresis register %u invalid, only 0...7 valid\n", + __func__, s->engine_id, reg - HYSTERESIS_CHANNEL_0); + break; + } + /* fallthrough */ + case BOUNDS_CHANNEL_0 ... BOUNDS_CHANNEL_7: + case HYSTERESIS_CHANNEL_0 ... HYSTERESIS_CHANNEL_7: + case ENGINE_CONTROL: + case INTERRUPT_CONTROL: + case VGA_DETECT_CONTROL: + case CLOCK_CONTROL: + case INTERRUPT_SOURCE: + case COMPENSATING_AND_TRIMMING: + value = s->regs[reg]; + break; + case DATA_CHANNEL_9_AND_8 ... DATA_CHANNEL_15_AND_14: + if (s->nr_channels <= 8) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: engine[%u]: " + "data register %u invalid, only 0...3 valid\n", + __func__, s->engine_id, reg - DATA_CHANNEL_1_AND_0); + break; + } + /* fallthrough */ + case DATA_CHANNEL_1_AND_0 ... DATA_CHANNEL_7_AND_6: + value = read_channel_sample(s, reg); + /* Allow 16-bit reads of the data registers */ + if (addr & 0x2) { + assert(size == 2); + value >>= 16; + } + break; + default: + qemu_log_mask(LOG_UNIMP, "%s: engine[%u]: 0x%" HWADDR_PRIx "\n", + __func__, s->engine_id, addr); + break; + } + + trace_aspeed_adc_engine_read(s->engine_id, addr, value); + return value; +} + +static void aspeed_adc_engine_write(void *opaque, hwaddr addr, uint64_t value, + unsigned int size) +{ + AspeedADCEngineState *s = ASPEED_ADC_ENGINE(opaque); + int reg = TO_REG(addr); + uint32_t init = 0; + + trace_aspeed_adc_engine_write(s->engine_id, addr, value); + + switch (reg) { + case ENGINE_CONTROL: + init = !!(value & ASPEED_ADC_ENGINE_EN); + init *= ASPEED_ADC_ENGINE_INIT; + + value &= ~ASPEED_ADC_ENGINE_INIT; + value |= init; + + value &= ~ASPEED_ADC_ENGINE_AUTO_COMP; + break; + case INTERRUPT_CONTROL: + case VGA_DETECT_CONTROL: + case CLOCK_CONTROL: + break; + case DATA_CHANNEL_9_AND_8 ... DATA_CHANNEL_15_AND_14: + if (s->nr_channels <= 8) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: engine[%u]: " + "data register %u invalid, only 0...3 valid\n", + __func__, s->engine_id, reg - DATA_CHANNEL_1_AND_0); + return; + } + /* fallthrough */ + case BOUNDS_CHANNEL_8 ... BOUNDS_CHANNEL_15: + if (s->nr_channels <= 8) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: engine[%u]: " + "bounds register %u invalid, only 0...7 valid\n", + __func__, s->engine_id, reg - BOUNDS_CHANNEL_0); + return; + } + /* fallthrough */ + case DATA_CHANNEL_1_AND_0 ... DATA_CHANNEL_7_AND_6: + case BOUNDS_CHANNEL_0 ... BOUNDS_CHANNEL_7: + value &= ASPEED_ADC_LH_MASK; + break; + case HYSTERESIS_CHANNEL_8 ... HYSTERESIS_CHANNEL_15: + if (s->nr_channels <= 8) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: engine[%u]: " + "hysteresis register %u invalid, only 0...7 valid\n", + __func__, s->engine_id, reg - HYSTERESIS_CHANNEL_0); + return; + } + /* fallthrough */ + case HYSTERESIS_CHANNEL_0 ... HYSTERESIS_CHANNEL_7: + value &= (ASPEED_ADC_HYST_EN | ASPEED_ADC_LH_MASK); + break; + case INTERRUPT_SOURCE: + value &= 0xffff; + break; + case COMPENSATING_AND_TRIMMING: + value &= 0xf; + break; + default: + qemu_log_mask(LOG_UNIMP, "%s: engine[%u]: " + "0x%" HWADDR_PRIx " 0x%" PRIx64 "\n", + __func__, s->engine_id, addr, value); + break; + } + + s->regs[reg] = value; +} + +static const MemoryRegionOps aspeed_adc_engine_ops = { + .read = aspeed_adc_engine_read, + .write = aspeed_adc_engine_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 2, + .max_access_size = 4, + .unaligned = false, + }, +}; + +static const uint32_t aspeed_adc_resets[ASPEED_ADC_NR_REGS] = { + [ENGINE_CONTROL] = 0x00000000, + [INTERRUPT_CONTROL] = 0x00000000, + [VGA_DETECT_CONTROL] = 0x0000000f, + [CLOCK_CONTROL] = 0x0000000f, +}; + +static void aspeed_adc_engine_reset(DeviceState *dev) +{ + AspeedADCEngineState *s = ASPEED_ADC_ENGINE(dev); + + memcpy(s->regs, aspeed_adc_resets, sizeof(aspeed_adc_resets)); +} + +static void aspeed_adc_engine_realize(DeviceState *dev, Error **errp) +{ + AspeedADCEngineState *s = ASPEED_ADC_ENGINE(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + g_autofree char *name = g_strdup_printf(TYPE_ASPEED_ADC_ENGINE ".%d", + s->engine_id); + + assert(s->engine_id < 2); + + sysbus_init_irq(sbd, &s->irq); + + memory_region_init_io(&s->mmio, OBJECT(s), &aspeed_adc_engine_ops, s, name, + ASPEED_ADC_ENGINE_MEMORY_REGION_SIZE); + + sysbus_init_mmio(sbd, &s->mmio); +} + +static const VMStateDescription vmstate_aspeed_adc_engine = { + .name = TYPE_ASPEED_ADC, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, AspeedADCEngineState, ASPEED_ADC_NR_REGS), + VMSTATE_END_OF_LIST(), + } +}; + +static Property aspeed_adc_engine_properties[] = { + DEFINE_PROP_UINT32("engine-id", AspeedADCEngineState, engine_id, 0), + DEFINE_PROP_UINT32("nr-channels", AspeedADCEngineState, nr_channels, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void aspeed_adc_engine_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = aspeed_adc_engine_realize; + dc->reset = aspeed_adc_engine_reset; + device_class_set_props(dc, aspeed_adc_engine_properties); + dc->desc = "Aspeed Analog-to-Digital Engine"; + dc->vmsd = &vmstate_aspeed_adc_engine; +} + +static const TypeInfo aspeed_adc_engine_info = { + .name = TYPE_ASPEED_ADC_ENGINE, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(AspeedADCEngineState), + .class_init = aspeed_adc_engine_class_init, +}; + +static void aspeed_adc_instance_init(Object *obj) +{ + AspeedADCState *s = ASPEED_ADC(obj); + AspeedADCClass *aac = ASPEED_ADC_GET_CLASS(obj); + uint32_t nr_channels = ASPEED_ADC_NR_CHANNELS / aac->nr_engines; + + for (int i = 0; i < aac->nr_engines; i++) { + AspeedADCEngineState *engine = &s->engines[i]; + object_initialize_child(obj, "engine[*]", engine, + TYPE_ASPEED_ADC_ENGINE); + qdev_prop_set_uint32(DEVICE(engine), "engine-id", i); + qdev_prop_set_uint32(DEVICE(engine), "nr-channels", nr_channels); + } +} + +static void aspeed_adc_set_irq(void *opaque, int n, int level) +{ + AspeedADCState *s = opaque; + AspeedADCClass *aac = ASPEED_ADC_GET_CLASS(s); + uint32_t pending = 0; + + /* TODO: update Global IRQ status register on AST2600 (Need specs) */ + for (int i = 0; i < aac->nr_engines; i++) { + uint32_t irq_status = s->engines[i].regs[INTERRUPT_CONTROL] & 0xFF; + pending |= irq_status << (i * 8); + } + + qemu_set_irq(s->irq, !!pending); +} + +static void aspeed_adc_realize(DeviceState *dev, Error **errp) +{ + AspeedADCState *s = ASPEED_ADC(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + AspeedADCClass *aac = ASPEED_ADC_GET_CLASS(dev); + + qdev_init_gpio_in_named_with_opaque(DEVICE(sbd), aspeed_adc_set_irq, + s, NULL, aac->nr_engines); + + sysbus_init_irq(sbd, &s->irq); + + memory_region_init(&s->mmio, OBJECT(s), TYPE_ASPEED_ADC, + ASPEED_ADC_MEMORY_REGION_SIZE); + + sysbus_init_mmio(sbd, &s->mmio); + + for (int i = 0; i < aac->nr_engines; i++) { + Object *eng = OBJECT(&s->engines[i]); + + if (!sysbus_realize(SYS_BUS_DEVICE(eng), errp)) { + return; + } + sysbus_connect_irq(SYS_BUS_DEVICE(eng), 0, + qdev_get_gpio_in(DEVICE(sbd), i)); + memory_region_add_subregion(&s->mmio, + i * ASPEED_ADC_ENGINE_MEMORY_REGION_SIZE, + &s->engines[i].mmio); + } +} + +static void aspeed_adc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + AspeedADCClass *aac = ASPEED_ADC_CLASS(klass); + + dc->realize = aspeed_adc_realize; + dc->desc = "Aspeed Analog-to-Digital Converter"; + aac->nr_engines = 1; +} + +static void aspeed_2600_adc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + AspeedADCClass *aac = ASPEED_ADC_CLASS(klass); + + dc->desc = "ASPEED 2600 ADC Controller"; + aac->nr_engines = 2; +} + +static const TypeInfo aspeed_adc_info = { + .name = TYPE_ASPEED_ADC, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_init = aspeed_adc_instance_init, + .instance_size = sizeof(AspeedADCState), + .class_init = aspeed_adc_class_init, + .class_size = sizeof(AspeedADCClass), + .abstract = true, +}; + +static const TypeInfo aspeed_2400_adc_info = { + .name = TYPE_ASPEED_2400_ADC, + .parent = TYPE_ASPEED_ADC, +}; + +static const TypeInfo aspeed_2500_adc_info = { + .name = TYPE_ASPEED_2500_ADC, + .parent = TYPE_ASPEED_ADC, +}; + +static const TypeInfo aspeed_2600_adc_info = { + .name = TYPE_ASPEED_2600_ADC, + .parent = TYPE_ASPEED_ADC, + .class_init = aspeed_2600_adc_class_init, +}; + +static void aspeed_adc_register_types(void) +{ + type_register_static(&aspeed_adc_engine_info); + type_register_static(&aspeed_adc_info); + type_register_static(&aspeed_2400_adc_info); + type_register_static(&aspeed_2500_adc_info); + type_register_static(&aspeed_2600_adc_info); +} + +type_init(aspeed_adc_register_types); diff --git a/hw/adc/meson.build b/hw/adc/meson.build index ac4f093fea..b29ac7ccdf 100644 --- a/hw/adc/meson.build +++ b/hw/adc/meson.build @@ -1,4 +1,5 @@ softmmu_ss.add(when: 'CONFIG_STM32F2XX_ADC', if_true: files('stm32f2xx_adc.c')) +softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_adc.c')) softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_adc.c')) softmmu_ss.add(when: 'CONFIG_ZYNQ', if_true: files('zynq-xadc.c')) softmmu_ss.add(when: 'CONFIG_MAX111X', if_true: files('max111x.c')) diff --git a/hw/adc/trace-events b/hw/adc/trace-events index 456f21c8f4..5a4c444d77 100644 --- a/hw/adc/trace-events +++ b/hw/adc/trace-events @@ -3,3 +3,6 @@ # npcm7xx_adc.c npcm7xx_adc_read(const char *id, uint64_t offset, uint32_t value) " %s offset: 0x%04" PRIx64 " value 0x%04" PRIx32 npcm7xx_adc_write(const char *id, uint64_t offset, uint32_t value) "%s offset: 0x%04" PRIx64 " value 0x%04" PRIx32 + +aspeed_adc_engine_read(uint32_t engine_id, uint64_t addr, uint64_t value) "engine[%u] 0x%" PRIx64 " 0x%" PRIx64 +aspeed_adc_engine_write(uint32_t engine_id, uint64_t addr, uint64_t value) "engine[%u] 0x%" PRIx64 " 0x%" PRIx64 diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index ba5f1dc5af..f5916e8126 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -274,18 +274,17 @@ static void aspeed_board_init_flashes(AspeedSMCState *s, int i ; for (i = 0; i < s->num_cs; ++i) { - AspeedSMCFlash *fl = &s->flashes[i]; DriveInfo *dinfo = drive_get_next(IF_MTD); qemu_irq cs_line; + DeviceState *dev; - fl->flash = qdev_new(flashtype); + dev = qdev_new(flashtype); if (dinfo) { - qdev_prop_set_drive(fl->flash, "drive", - blk_by_legacy_dinfo(dinfo)); + qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(dinfo)); } - qdev_realize_and_unref(fl->flash, BUS(s->spi), &error_fatal); + qdev_realize_and_unref(dev, BUS(s->spi), &error_fatal); - cs_line = qdev_get_gpio_in_named(fl->flash, SSI_GPIO_CS, 0); + cs_line = qdev_get_gpio_in_named(dev, SSI_GPIO_CS, 0); sysbus_connect_irq(SYS_BUS_DEVICE(s), i + 1, cs_line); } } @@ -377,6 +376,7 @@ static void aspeed_machine_init(MachineState *machine) if (drive0) { AspeedSMCFlash *fl = &bmc->soc.fmc.flashes[0]; MemoryRegion *boot_rom = g_new(MemoryRegion, 1); + uint64_t size = memory_region_size(&fl->mmio); /* * create a ROM region using the default mapping window size of @@ -386,15 +386,15 @@ static void aspeed_machine_init(MachineState *machine) */ if (ASPEED_MACHINE(machine)->mmio_exec) { memory_region_init_alias(boot_rom, NULL, "aspeed.boot_rom", - &fl->mmio, 0, fl->size); + &fl->mmio, 0, size); memory_region_add_subregion(get_system_memory(), FIRMWARE_ADDR, boot_rom); } else { memory_region_init_rom(boot_rom, NULL, "aspeed.boot_rom", - fl->size, &error_abort); + size, &error_abort); memory_region_add_subregion(get_system_memory(), FIRMWARE_ADDR, boot_rom); - write_boot_rom(drive0, FIRMWARE_ADDR, fl->size, &error_abort); + write_boot_rom(drive0, FIRMWARE_ADDR, size, &error_abort); } } diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index 9d70e8e060..0384357a95 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -148,6 +148,9 @@ static void aspeed_soc_ast2600_init(Object *obj) 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); @@ -322,6 +325,14 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->timerctrl), i, irq); } + /* ADC */ + if (!sysbus_realize(SYS_BUS_DEVICE(&s->adc), errp)) { + return; + } + sysbus_mmio_map(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 - attach an 8250 to the IO space as our UART */ serial_mm_init(get_system_memory(), sc->memmap[s->uart_default], 2, aspeed_soc_get_irq(s, s->uart_default), 38400, @@ -337,11 +348,8 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) 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 SoC has one IRQ per I2C bus. Skip the common - * IRQ (AST2400 and AST2500) and connect all bussses. - */ - sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c), i + 1, irq); + /* The AST2600 I2C controller has one IRQ per bus. */ + sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c.busses[i]), 0, irq); } /* FMC, The number of CS is set at the board level */ @@ -352,7 +360,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) } sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 0, sc->memmap[ASPEED_DEV_FMC]); sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 1, - s->fmc.ctrl->flash_window_base); + 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)); @@ -367,7 +375,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0, sc->memmap[ASPEED_DEV_SPI1 + i]); sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 1, - s->spi[i].ctrl->flash_window_base); + ASPEED_SMC_GET_CLASS(&s->spi[i])->flash_window_base); } /* EHCI */ diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index ed84502e23..7d53cf2f51 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -162,6 +162,9 @@ static void aspeed_soc_init(Object *obj) 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); @@ -287,6 +290,14 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->timerctrl), i, irq); } + /* ADC */ + if (!sysbus_realize(SYS_BUS_DEVICE(&s->adc), errp)) { + return; + } + sysbus_mmio_map(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 - attach an 8250 to the IO space as our UART */ serial_mm_init(get_system_memory(), sc->memmap[s->uart_default], 2, aspeed_soc_get_irq(s, s->uart_default), 38400, @@ -310,7 +321,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) } sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 0, sc->memmap[ASPEED_DEV_FMC]); sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 1, - s->fmc.ctrl->flash_window_base); + 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)); @@ -323,7 +334,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp) sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0, sc->memmap[ASPEED_DEV_SPI1 + i]); sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 1, - s->spi[i].ctrl->flash_window_base); + ASPEED_SMC_GET_CLASS(&s->spi[i])->flash_window_base); } /* EHCI */ diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c index dfa6d6cb40..911d21c8cf 100644 --- a/hw/gpio/aspeed_gpio.c +++ b/hw/gpio/aspeed_gpio.c @@ -16,11 +16,7 @@ #include "hw/irq.h" #include "migration/vmstate.h" -#define GPIOS_PER_REG 32 -#define GPIOS_PER_SET GPIOS_PER_REG -#define GPIO_PIN_GAP_SIZE 4 #define GPIOS_PER_GROUP 8 -#define GPIO_GROUP_SHIFT 3 /* GPIO Source Types */ #define ASPEED_CMD_SRC_MASK 0x01010101 @@ -259,7 +255,7 @@ static void aspeed_gpio_update(AspeedGPIOState *s, GPIOSets *regs, diff = old ^ new; if (diff) { - for (gpio = 0; gpio < GPIOS_PER_REG; gpio++) { + for (gpio = 0; gpio < ASPEED_GPIOS_PER_SET; gpio++) { uint32_t mask = 1 << gpio; /* If the gpio needs to be updated... */ @@ -283,8 +279,7 @@ static void aspeed_gpio_update(AspeedGPIOState *s, GPIOSets *regs, if (direction & mask) { /* ...trigger the line-state IRQ */ ptrdiff_t set = aspeed_gpio_set_idx(s, regs); - size_t offset = set * GPIOS_PER_SET + gpio; - qemu_set_irq(s->gpios[offset], !!(new & mask)); + qemu_set_irq(s->gpios[set][gpio], !!(new & mask)); } else { /* ...otherwise if we meet the line's current IRQ policy... */ if (aspeed_evaluate_irq(regs, old & mask, gpio)) { @@ -297,21 +292,6 @@ static void aspeed_gpio_update(AspeedGPIOState *s, GPIOSets *regs, qemu_set_irq(s->irq, !!(s->pending)); } -static uint32_t aspeed_adjust_pin(AspeedGPIOState *s, uint32_t pin) -{ - AspeedGPIOClass *agc = ASPEED_GPIO_GET_CLASS(s); - /* - * The 2500 has a 4 pin gap in group AB and the 2400 has a 4 pin - * gap in group Y (and only four pins in AB but this is the last group so - * it doesn't matter). - */ - if (agc->gap && pin >= agc->gap) { - pin += GPIO_PIN_GAP_SIZE; - } - - return pin; -} - static bool aspeed_gpio_get_pin_level(AspeedGPIOState *s, uint32_t set_idx, uint32_t pin) { @@ -367,7 +347,7 @@ static uint32_t update_value_control_source(GPIOSets *regs, uint32_t old_value, uint32_t new_value = 0; /* for each group in set */ - for (i = 0; i < GPIOS_PER_REG; i += GPIOS_PER_GROUP) { + for (i = 0; i < ASPEED_GPIOS_PER_SET; i += GPIOS_PER_GROUP) { cmd_source = extract32(regs->cmd_source_0, i, 1) | (extract32(regs->cmd_source_1, i, 1) << 1); @@ -637,7 +617,7 @@ static void aspeed_gpio_write(void *opaque, hwaddr offset, uint64_t data, * bidirectional | 1 | 1 | data * input only | 1 | 0 | 0 * output only | 0 | 1 | 1 - * no pin / gap | 0 | 0 | 0 + * no pin | 0 | 0 | 0 * * which is captured by: * data = ( data | ~input) & output; @@ -779,7 +759,7 @@ static void aspeed_gpio_set_pin(Object *obj, Visitor *v, const char *name, } /****************** Setup functions ******************/ -static const GPIOSetProperties ast2400_set_props[] = { +static const GPIOSetProperties ast2400_set_props[ASPEED_GPIO_MAX_NR_SETS] = { [0] = {0xffffffff, 0xffffffff, {"A", "B", "C", "D"} }, [1] = {0xffffffff, 0xffffffff, {"E", "F", "G", "H"} }, [2] = {0xffffffff, 0xffffffff, {"I", "J", "K", "L"} }, @@ -789,28 +769,28 @@ static const GPIOSetProperties ast2400_set_props[] = { [6] = {0x0000000f, 0x0fffff0f, {"Y", "Z", "AA", "AB"} }, }; -static const GPIOSetProperties ast2500_set_props[] = { +static const GPIOSetProperties ast2500_set_props[ASPEED_GPIO_MAX_NR_SETS] = { [0] = {0xffffffff, 0xffffffff, {"A", "B", "C", "D"} }, [1] = {0xffffffff, 0xffffffff, {"E", "F", "G", "H"} }, [2] = {0xffffffff, 0xffffffff, {"I", "J", "K", "L"} }, [3] = {0xffffffff, 0xffffffff, {"M", "N", "O", "P"} }, [4] = {0xffffffff, 0xffffffff, {"Q", "R", "S", "T"} }, [5] = {0xffffffff, 0x0000ffff, {"U", "V", "W", "X"} }, - [6] = {0xffffff0f, 0x0fffff0f, {"Y", "Z", "AA", "AB"} }, + [6] = {0x0fffffff, 0x0fffffff, {"Y", "Z", "AA", "AB"} }, [7] = {0x000000ff, 0x000000ff, {"AC"} }, }; -static GPIOSetProperties ast2600_3_3v_set_props[] = { +static GPIOSetProperties ast2600_3_3v_set_props[ASPEED_GPIO_MAX_NR_SETS] = { [0] = {0xffffffff, 0xffffffff, {"A", "B", "C", "D"} }, [1] = {0xffffffff, 0xffffffff, {"E", "F", "G", "H"} }, [2] = {0xffffffff, 0xffffffff, {"I", "J", "K", "L"} }, [3] = {0xffffffff, 0xffffffff, {"M", "N", "O", "P"} }, - [4] = {0xffffffff, 0xffffffff, {"Q", "R", "S", "T"} }, - [5] = {0xffffffff, 0x0000ffff, {"U", "V", "W", "X"} }, - [6] = {0xffff0000, 0x0fff0000, {"Y", "Z", "", ""} }, + [4] = {0xffffffff, 0x00ffffff, {"Q", "R", "S", "T"} }, + [5] = {0xffffffff, 0xffffff00, {"U", "V", "W", "X"} }, + [6] = {0x0000ffff, 0x0000ffff, {"Y", "Z"} }, }; -static GPIOSetProperties ast2600_1_8v_set_props[] = { +static GPIOSetProperties ast2600_1_8v_set_props[ASPEED_GPIO_MAX_NR_SETS] = { [0] = {0xffffffff, 0xffffffff, {"18A", "18B", "18C", "18D"} }, [1] = {0x0000000f, 0x0000000f, {"18E"} }, }; @@ -836,14 +816,20 @@ static void aspeed_gpio_realize(DeviceState *dev, Error **errp) AspeedGPIOState *s = ASPEED_GPIO(dev); SysBusDevice *sbd = SYS_BUS_DEVICE(dev); AspeedGPIOClass *agc = ASPEED_GPIO_GET_CLASS(s); - int pin; /* Interrupt parent line */ sysbus_init_irq(sbd, &s->irq); /* Individual GPIOs */ - for (pin = 0; pin < agc->nr_gpio_pins; pin++) { - sysbus_init_irq(sbd, &s->gpios[pin]); + for (int i = 0; i < ASPEED_GPIO_MAX_NR_SETS; i++) { + const GPIOSetProperties *props = &agc->props[i]; + uint32_t skip = ~(props->input | props->output); + for (int j = 0; j < ASPEED_GPIOS_PER_SET; j++) { + if (skip >> j & 1) { + continue; + } + sysbus_init_irq(sbd, &s->gpios[i][j]); + } } memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_gpio_ops, s, @@ -856,20 +842,22 @@ static void aspeed_gpio_init(Object *obj) { AspeedGPIOState *s = ASPEED_GPIO(obj); AspeedGPIOClass *agc = ASPEED_GPIO_GET_CLASS(s); - int pin; - for (pin = 0; pin < agc->nr_gpio_pins; pin++) { - char *name; - int set_idx = pin / GPIOS_PER_SET; - int pin_idx = aspeed_adjust_pin(s, pin) - (set_idx * GPIOS_PER_SET); - int group_idx = pin_idx >> GPIO_GROUP_SHIFT; - const GPIOSetProperties *props = &agc->props[set_idx]; - - name = g_strdup_printf("gpio%s%d", props->group_label[group_idx], - pin_idx % GPIOS_PER_GROUP); - object_property_add(obj, name, "bool", aspeed_gpio_get_pin, - aspeed_gpio_set_pin, NULL, NULL); - g_free(name); + for (int i = 0; i < ASPEED_GPIO_MAX_NR_SETS; i++) { + const GPIOSetProperties *props = &agc->props[i]; + uint32_t skip = ~(props->input | props->output); + for (int j = 0; j < ASPEED_GPIOS_PER_SET; j++) { + if (skip >> j & 1) { + continue; + } + int group_idx = j / GPIOS_PER_GROUP; + int pin_idx = j % GPIOS_PER_GROUP; + const char *group = &props->group_label[group_idx][0]; + char *name = g_strdup_printf("gpio%s%d", group, pin_idx); + object_property_add(obj, name, "bool", aspeed_gpio_get_pin, + aspeed_gpio_set_pin, NULL, NULL); + g_free(name); + } } } @@ -926,7 +914,6 @@ static void aspeed_gpio_ast2400_class_init(ObjectClass *klass, void *data) agc->props = ast2400_set_props; agc->nr_gpio_pins = 216; agc->nr_gpio_sets = 7; - agc->gap = 196; agc->reg_table = aspeed_3_3v_gpios; } @@ -937,7 +924,6 @@ static void aspeed_gpio_2500_class_init(ObjectClass *klass, void *data) agc->props = ast2500_set_props; agc->nr_gpio_pins = 228; agc->nr_gpio_sets = 8; - agc->gap = 220; agc->reg_table = aspeed_3_3v_gpios; } diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c index 8d276d9ed3..03a4f5a910 100644 --- a/hw/i2c/aspeed_i2c.c +++ b/hw/i2c/aspeed_i2c.c @@ -740,20 +740,20 @@ static const VMStateDescription aspeed_i2c_vmstate = { static void aspeed_i2c_reset(DeviceState *dev) { - int i; AspeedI2CState *s = ASPEED_I2C(dev); - AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s); s->intr_status = 0; +} + +static void aspeed_i2c_instance_init(Object *obj) +{ + AspeedI2CState *s = ASPEED_I2C(obj); + AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s); + int i; for (i = 0; i < aic->num_busses; i++) { - s->busses[i].intr_ctrl = 0; - s->busses[i].intr_status = 0; - s->busses[i].cmd = 0; - s->busses[i].buf = 0; - s->busses[i].dma_addr = 0; - s->busses[i].dma_len = 0; - i2c_end_transfer(s->busses[i].bus); + object_initialize_child(obj, "bus[*]", &s->busses[i], + TYPE_ASPEED_I2C_BUS); } } @@ -791,17 +791,21 @@ static void aspeed_i2c_realize(DeviceState *dev, Error **errp) sysbus_init_mmio(sbd, &s->iomem); for (i = 0; i < aic->num_busses; i++) { - char name[32]; + Object *bus = OBJECT(&s->busses[i]); int offset = i < aic->gap ? 1 : 5; - sysbus_init_irq(sbd, &s->busses[i].irq); - snprintf(name, sizeof(name), "aspeed.i2c.%d", i); - s->busses[i].controller = s; - s->busses[i].id = i; - s->busses[i].bus = i2c_init_bus(dev, name); - memory_region_init_io(&s->busses[i].mr, OBJECT(dev), - &aspeed_i2c_bus_ops, &s->busses[i], name, - aic->reg_size); + if (!object_property_set_link(bus, "controller", OBJECT(s), errp)) { + return; + } + + if (!object_property_set_uint(bus, "bus-id", i, errp)) { + return; + } + + if (!sysbus_realize(SYS_BUS_DEVICE(bus), errp)) { + return; + } + memory_region_add_subregion(&s->iomem, aic->reg_size * (i + offset), &s->busses[i].mr); } @@ -841,12 +845,72 @@ static void aspeed_i2c_class_init(ObjectClass *klass, void *data) static const TypeInfo aspeed_i2c_info = { .name = TYPE_ASPEED_I2C, .parent = TYPE_SYS_BUS_DEVICE, + .instance_init = aspeed_i2c_instance_init, .instance_size = sizeof(AspeedI2CState), .class_init = aspeed_i2c_class_init, .class_size = sizeof(AspeedI2CClass), .abstract = true, }; +static void aspeed_i2c_bus_reset(DeviceState *dev) +{ + AspeedI2CBus *s = ASPEED_I2C_BUS(dev); + + s->intr_ctrl = 0; + s->intr_status = 0; + s->cmd = 0; + s->buf = 0; + s->dma_addr = 0; + s->dma_len = 0; + i2c_end_transfer(s->bus); +} + +static void aspeed_i2c_bus_realize(DeviceState *dev, Error **errp) +{ + AspeedI2CBus *s = ASPEED_I2C_BUS(dev); + AspeedI2CClass *aic; + g_autofree char *name = g_strdup_printf(TYPE_ASPEED_I2C_BUS ".%d", s->id); + + if (!s->controller) { + error_setg(errp, TYPE_ASPEED_I2C_BUS ": 'controller' link not set"); + return; + } + + aic = ASPEED_I2C_GET_CLASS(s->controller); + + sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq); + + s->bus = i2c_init_bus(dev, name); + + memory_region_init_io(&s->mr, OBJECT(s), &aspeed_i2c_bus_ops, + s, name, aic->reg_size); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mr); +} + +static Property aspeed_i2c_bus_properties[] = { + DEFINE_PROP_UINT8("bus-id", AspeedI2CBus, id, 0), + DEFINE_PROP_LINK("controller", AspeedI2CBus, controller, TYPE_ASPEED_I2C, + AspeedI2CState *), + DEFINE_PROP_END_OF_LIST(), +}; + +static void aspeed_i2c_bus_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->desc = "Aspeed I2C Bus"; + dc->realize = aspeed_i2c_bus_realize; + dc->reset = aspeed_i2c_bus_reset; + device_class_set_props(dc, aspeed_i2c_bus_properties); +} + +static const TypeInfo aspeed_i2c_bus_info = { + .name = TYPE_ASPEED_I2C_BUS, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(AspeedI2CBus), + .class_init = aspeed_i2c_bus_class_init, +}; + static qemu_irq aspeed_2400_i2c_bus_get_irq(AspeedI2CBus *bus) { return bus->controller->irq; @@ -951,6 +1015,7 @@ static const TypeInfo aspeed_2600_i2c_info = { static void aspeed_i2c_register_types(void) { + type_register_static(&aspeed_i2c_bus_info); type_register_static(&aspeed_i2c_info); type_register_static(&aspeed_2400_i2c_info); type_register_static(&aspeed_2500_i2c_info); diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c index 331a2c5446..8a988c1676 100644 --- a/hw/ssi/aspeed_smc.c +++ b/hw/ssi/aspeed_smc.c @@ -124,6 +124,13 @@ /* SPI dummy cycle data */ #define R_DUMMY_DATA (0x54 / 4) +/* FMC_WDT2 Control/Status Register for Alternate Boot (AST2600) */ +#define R_FMC_WDT2_CTRL (0x64 / 4) +#define FMC_WDT2_CTRL_ALT_BOOT_MODE BIT(6) /* O: 2 chips 1: 1 chip */ +#define FMC_WDT2_CTRL_SINGLE_BOOT_MODE BIT(5) +#define FMC_WDT2_CTRL_BOOT_SOURCE BIT(4) /* O: primary 1: alternate */ +#define FMC_WDT2_CTRL_EN BIT(0) + /* DMA Control/Status Register */ #define R_DMA_CTRL (0x80 / 4) #define DMA_CTRL_REQUEST (1 << 31) @@ -162,11 +169,6 @@ #define ASPEED_SMC_R_SPI_MAX (0x20 / 4) #define ASPEED_SMC_R_SMC_MAX (0x20 / 4) -#define ASPEED_SOC_SMC_FLASH_BASE 0x10000000 -#define ASPEED_SOC_FMC_FLASH_BASE 0x20000000 -#define ASPEED_SOC_SPI_FLASH_BASE 0x30000000 -#define ASPEED_SOC_SPI2_FLASH_BASE 0x38000000 - /* * DMA DRAM addresses should be 4 bytes aligned and the valid address * range is 0x40000000 - 0x5FFFFFFF (AST2400) @@ -179,8 +181,8 @@ * 0: 4 bytes * 0x7FFFFF: 32M bytes */ -#define DMA_DRAM_ADDR(s, val) ((val) & (s)->ctrl->dma_dram_mask) -#define DMA_FLASH_ADDR(s, val) ((val) & (s)->ctrl->dma_flash_mask) +#define DMA_DRAM_ADDR(asc, val) ((val) & (asc)->dma_dram_mask) +#define DMA_FLASH_ADDR(asc, val) ((val) & (asc)->dma_flash_mask) #define DMA_LENGTH(val) ((val) & 0x01FFFFFC) /* Flash opcodes. */ @@ -194,332 +196,48 @@ * controller. These can be changed when board is initialized with the * Segment Address Registers. */ -static const AspeedSegments aspeed_segments_legacy[] = { - { 0x10000000, 32 * 1024 * 1024 }, -}; - -static const AspeedSegments aspeed_segments_fmc[] = { - { 0x20000000, 64 * 1024 * 1024 }, /* start address is readonly */ - { 0x24000000, 32 * 1024 * 1024 }, - { 0x26000000, 32 * 1024 * 1024 }, - { 0x28000000, 32 * 1024 * 1024 }, - { 0x2A000000, 32 * 1024 * 1024 } -}; - -static const AspeedSegments aspeed_segments_spi[] = { - { 0x30000000, 64 * 1024 * 1024 }, -}; - -static const AspeedSegments aspeed_segments_ast2500_fmc[] = { - { 0x20000000, 128 * 1024 * 1024 }, /* start address is readonly */ - { 0x28000000, 32 * 1024 * 1024 }, - { 0x2A000000, 32 * 1024 * 1024 }, -}; - -static const AspeedSegments aspeed_segments_ast2500_spi1[] = { - { 0x30000000, 32 * 1024 * 1024 }, /* start address is readonly */ - { 0x32000000, 96 * 1024 * 1024 }, /* end address is readonly */ -}; - -static const AspeedSegments aspeed_segments_ast2500_spi2[] = { - { 0x38000000, 32 * 1024 * 1024 }, /* start address is readonly */ - { 0x3A000000, 96 * 1024 * 1024 }, /* end address is readonly */ -}; -static uint32_t aspeed_smc_segment_to_reg(const AspeedSMCState *s, - const AspeedSegments *seg); -static void aspeed_smc_reg_to_segment(const AspeedSMCState *s, uint32_t reg, - AspeedSegments *seg); -static void aspeed_smc_dma_ctrl(AspeedSMCState *s, uint32_t value); - -/* - * AST2600 definitions - */ -#define ASPEED26_SOC_FMC_FLASH_BASE 0x20000000 -#define ASPEED26_SOC_SPI_FLASH_BASE 0x30000000 -#define ASPEED26_SOC_SPI2_FLASH_BASE 0x50000000 - -static const AspeedSegments aspeed_segments_ast2600_fmc[] = { - { 0x0, 128 * MiB }, /* start address is readonly */ - { 128 * MiB, 128 * MiB }, /* default is disabled but needed for -kernel */ - { 0x0, 0 }, /* disabled */ -}; - -static const AspeedSegments aspeed_segments_ast2600_spi1[] = { - { 0x0, 128 * MiB }, /* start address is readonly */ - { 0x0, 0 }, /* disabled */ -}; - -static const AspeedSegments aspeed_segments_ast2600_spi2[] = { - { 0x0, 128 * MiB }, /* start address is readonly */ - { 0x0, 0 }, /* disabled */ - { 0x0, 0 }, /* disabled */ -}; - -static uint32_t aspeed_2600_smc_segment_to_reg(const AspeedSMCState *s, - const AspeedSegments *seg); -static void aspeed_2600_smc_reg_to_segment(const AspeedSMCState *s, - uint32_t reg, AspeedSegments *seg); -static void aspeed_2600_smc_dma_ctrl(AspeedSMCState *s, uint32_t value); +static const AspeedSegments aspeed_2500_spi1_segments[]; +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 -static inline bool aspeed_smc_has_dma(const AspeedSMCState *s) +static inline bool aspeed_smc_has_dma(const AspeedSMCClass *asc) { - return !!(s->ctrl->features & ASPEED_SMC_FEATURE_DMA); + return !!(asc->features & ASPEED_SMC_FEATURE_DMA); } -static const AspeedSMCController controllers[] = { - { - .name = "aspeed.smc-ast2400", - .r_conf = R_CONF, - .r_ce_ctrl = R_CE_CTRL, - .r_ctrl0 = R_CTRL0, - .r_timings = R_TIMINGS, - .nregs_timings = 1, - .conf_enable_w0 = CONF_ENABLE_W0, - .max_peripherals = 1, - .segments = aspeed_segments_legacy, - .flash_window_base = ASPEED_SOC_SMC_FLASH_BASE, - .flash_window_size = 0x6000000, - .features = 0x0, - .nregs = ASPEED_SMC_R_SMC_MAX, - .segment_to_reg = aspeed_smc_segment_to_reg, - .reg_to_segment = aspeed_smc_reg_to_segment, - .dma_ctrl = aspeed_smc_dma_ctrl, - }, { - .name = "aspeed.fmc-ast2400", - .r_conf = R_CONF, - .r_ce_ctrl = R_CE_CTRL, - .r_ctrl0 = R_CTRL0, - .r_timings = R_TIMINGS, - .nregs_timings = 1, - .conf_enable_w0 = CONF_ENABLE_W0, - .max_peripherals = 5, - .segments = aspeed_segments_fmc, - .flash_window_base = ASPEED_SOC_FMC_FLASH_BASE, - .flash_window_size = 0x10000000, - .features = ASPEED_SMC_FEATURE_DMA, - .dma_flash_mask = 0x0FFFFFFC, - .dma_dram_mask = 0x1FFFFFFC, - .nregs = ASPEED_SMC_R_MAX, - .segment_to_reg = aspeed_smc_segment_to_reg, - .reg_to_segment = aspeed_smc_reg_to_segment, - .dma_ctrl = aspeed_smc_dma_ctrl, - }, { - .name = "aspeed.spi1-ast2400", - .r_conf = R_SPI_CONF, - .r_ce_ctrl = 0xff, - .r_ctrl0 = R_SPI_CTRL0, - .r_timings = R_SPI_TIMINGS, - .nregs_timings = 1, - .conf_enable_w0 = SPI_CONF_ENABLE_W0, - .max_peripherals = 1, - .segments = aspeed_segments_spi, - .flash_window_base = ASPEED_SOC_SPI_FLASH_BASE, - .flash_window_size = 0x10000000, - .features = 0x0, - .nregs = ASPEED_SMC_R_SPI_MAX, - .segment_to_reg = aspeed_smc_segment_to_reg, - .reg_to_segment = aspeed_smc_reg_to_segment, - .dma_ctrl = aspeed_smc_dma_ctrl, - }, { - .name = "aspeed.fmc-ast2500", - .r_conf = R_CONF, - .r_ce_ctrl = R_CE_CTRL, - .r_ctrl0 = R_CTRL0, - .r_timings = R_TIMINGS, - .nregs_timings = 1, - .conf_enable_w0 = CONF_ENABLE_W0, - .max_peripherals = 3, - .segments = aspeed_segments_ast2500_fmc, - .flash_window_base = ASPEED_SOC_FMC_FLASH_BASE, - .flash_window_size = 0x10000000, - .features = ASPEED_SMC_FEATURE_DMA, - .dma_flash_mask = 0x0FFFFFFC, - .dma_dram_mask = 0x3FFFFFFC, - .nregs = ASPEED_SMC_R_MAX, - .segment_to_reg = aspeed_smc_segment_to_reg, - .reg_to_segment = aspeed_smc_reg_to_segment, - .dma_ctrl = aspeed_smc_dma_ctrl, - }, { - .name = "aspeed.spi1-ast2500", - .r_conf = R_CONF, - .r_ce_ctrl = R_CE_CTRL, - .r_ctrl0 = R_CTRL0, - .r_timings = R_TIMINGS, - .nregs_timings = 1, - .conf_enable_w0 = CONF_ENABLE_W0, - .max_peripherals = 2, - .segments = aspeed_segments_ast2500_spi1, - .flash_window_base = ASPEED_SOC_SPI_FLASH_BASE, - .flash_window_size = 0x8000000, - .features = 0x0, - .nregs = ASPEED_SMC_R_MAX, - .segment_to_reg = aspeed_smc_segment_to_reg, - .reg_to_segment = aspeed_smc_reg_to_segment, - .dma_ctrl = aspeed_smc_dma_ctrl, - }, { - .name = "aspeed.spi2-ast2500", - .r_conf = R_CONF, - .r_ce_ctrl = R_CE_CTRL, - .r_ctrl0 = R_CTRL0, - .r_timings = R_TIMINGS, - .nregs_timings = 1, - .conf_enable_w0 = CONF_ENABLE_W0, - .max_peripherals = 2, - .segments = aspeed_segments_ast2500_spi2, - .flash_window_base = ASPEED_SOC_SPI2_FLASH_BASE, - .flash_window_size = 0x8000000, - .features = 0x0, - .nregs = ASPEED_SMC_R_MAX, - .segment_to_reg = aspeed_smc_segment_to_reg, - .reg_to_segment = aspeed_smc_reg_to_segment, - .dma_ctrl = aspeed_smc_dma_ctrl, - }, { - .name = "aspeed.fmc-ast2600", - .r_conf = R_CONF, - .r_ce_ctrl = R_CE_CTRL, - .r_ctrl0 = R_CTRL0, - .r_timings = R_TIMINGS, - .nregs_timings = 1, - .conf_enable_w0 = CONF_ENABLE_W0, - .max_peripherals = 3, - .segments = aspeed_segments_ast2600_fmc, - .flash_window_base = ASPEED26_SOC_FMC_FLASH_BASE, - .flash_window_size = 0x10000000, - .features = ASPEED_SMC_FEATURE_DMA, - .dma_flash_mask = 0x0FFFFFFC, - .dma_dram_mask = 0x3FFFFFFC, - .nregs = ASPEED_SMC_R_MAX, - .segment_to_reg = aspeed_2600_smc_segment_to_reg, - .reg_to_segment = aspeed_2600_smc_reg_to_segment, - .dma_ctrl = aspeed_2600_smc_dma_ctrl, - }, { - .name = "aspeed.spi1-ast2600", - .r_conf = R_CONF, - .r_ce_ctrl = R_CE_CTRL, - .r_ctrl0 = R_CTRL0, - .r_timings = R_TIMINGS, - .nregs_timings = 2, - .conf_enable_w0 = CONF_ENABLE_W0, - .max_peripherals = 2, - .segments = aspeed_segments_ast2600_spi1, - .flash_window_base = ASPEED26_SOC_SPI_FLASH_BASE, - .flash_window_size = 0x10000000, - .features = ASPEED_SMC_FEATURE_DMA | - ASPEED_SMC_FEATURE_DMA_GRANT, - .dma_flash_mask = 0x0FFFFFFC, - .dma_dram_mask = 0x3FFFFFFC, - .nregs = ASPEED_SMC_R_MAX, - .segment_to_reg = aspeed_2600_smc_segment_to_reg, - .reg_to_segment = aspeed_2600_smc_reg_to_segment, - .dma_ctrl = aspeed_2600_smc_dma_ctrl, - }, { - .name = "aspeed.spi2-ast2600", - .r_conf = R_CONF, - .r_ce_ctrl = R_CE_CTRL, - .r_ctrl0 = R_CTRL0, - .r_timings = R_TIMINGS, - .nregs_timings = 3, - .conf_enable_w0 = CONF_ENABLE_W0, - .max_peripherals = 3, - .segments = aspeed_segments_ast2600_spi2, - .flash_window_base = ASPEED26_SOC_SPI2_FLASH_BASE, - .flash_window_size = 0x10000000, - .features = ASPEED_SMC_FEATURE_DMA | - ASPEED_SMC_FEATURE_DMA_GRANT, - .dma_flash_mask = 0x0FFFFFFC, - .dma_dram_mask = 0x3FFFFFFC, - .nregs = ASPEED_SMC_R_MAX, - .segment_to_reg = aspeed_2600_smc_segment_to_reg, - .reg_to_segment = aspeed_2600_smc_reg_to_segment, - .dma_ctrl = aspeed_2600_smc_dma_ctrl, - }, -}; - -/* - * The Segment Registers of the AST2400 and AST2500 have a 8MB - * unit. The address range of a flash SPI peripheral is encoded with - * absolute addresses which should be part of the overall controller - * window. - */ -static uint32_t aspeed_smc_segment_to_reg(const AspeedSMCState *s, - const AspeedSegments *seg) +static inline bool aspeed_smc_has_wdt_control(const AspeedSMCClass *asc) { - uint32_t reg = 0; - reg |= ((seg->addr >> 23) & SEG_START_MASK) << SEG_START_SHIFT; - reg |= (((seg->addr + seg->size) >> 23) & SEG_END_MASK) << SEG_END_SHIFT; - return reg; + return !!(asc->features & ASPEED_SMC_FEATURE_WDT_CONTROL); } -static void aspeed_smc_reg_to_segment(const AspeedSMCState *s, - uint32_t reg, AspeedSegments *seg) -{ - seg->addr = ((reg >> SEG_START_SHIFT) & SEG_START_MASK) << 23; - seg->size = (((reg >> SEG_END_SHIFT) & SEG_END_MASK) << 23) - seg->addr; -} - -/* - * The Segment Registers of the AST2600 have a 1MB unit. The address - * range of a flash SPI peripheral is encoded with offsets in the overall - * controller window. The previous SoC AST2400 and AST2500 used - * absolute addresses. Only bits [27:20] are relevant and the end - * address is an upper bound limit. - */ -#define AST2600_SEG_ADDR_MASK 0x0ff00000 - -static uint32_t aspeed_2600_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 & AST2600_SEG_ADDR_MASK) >> 16; /* start offset */ - reg |= (seg->addr + seg->size - 1) & AST2600_SEG_ADDR_MASK; /* end offset */ - return reg; -} - -static void aspeed_2600_smc_reg_to_segment(const AspeedSMCState *s, - uint32_t reg, AspeedSegments *seg) -{ - uint32_t start_offset = (reg << 16) & AST2600_SEG_ADDR_MASK; - uint32_t end_offset = reg & AST2600_SEG_ADDR_MASK; - - if (reg) { - seg->addr = s->ctrl->flash_window_base + start_offset; - seg->size = end_offset + MiB - start_offset; - } else { - seg->addr = s->ctrl->flash_window_base; - seg->size = 0; - } -} +#define aspeed_smc_error(fmt, ...) \ + qemu_log_mask(LOG_GUEST_ERROR, "%s: " fmt "\n", __func__, ## __VA_ARGS__) static bool aspeed_smc_flash_overlap(const AspeedSMCState *s, const AspeedSegments *new, int cs) { + AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s); AspeedSegments seg; int i; - for (i = 0; i < s->ctrl->max_peripherals; i++) { + for (i = 0; i < asc->max_peripherals; i++) { if (i == cs) { continue; } - s->ctrl->reg_to_segment(s, s->regs[R_SEG_ADDR0 + i], &seg); + asc->reg_to_segment(s, s->regs[R_SEG_ADDR0 + i], &seg); if (new->addr + new->size > seg.addr && new->addr < seg.addr + seg.size) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: new segment CS%d [ 0x%" - HWADDR_PRIx" - 0x%"HWADDR_PRIx" ] overlaps with " - "CS%d [ 0x%"HWADDR_PRIx" - 0x%"HWADDR_PRIx" ]\n", - s->ctrl->name, cs, new->addr, new->addr + new->size, - i, seg.addr, seg.addr + seg.size); + aspeed_smc_error("new segment CS%d [ 0x%" + HWADDR_PRIx" - 0x%"HWADDR_PRIx" ] overlaps with " + "CS%d [ 0x%"HWADDR_PRIx" - 0x%"HWADDR_PRIx" ]", + cs, new->addr, new->addr + new->size, + i, seg.addr, seg.addr + seg.size); return true; } } @@ -529,14 +247,15 @@ static bool aspeed_smc_flash_overlap(const AspeedSMCState *s, static void aspeed_smc_flash_set_segment_region(AspeedSMCState *s, int cs, uint64_t regval) { + AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s); AspeedSMCFlash *fl = &s->flashes[cs]; AspeedSegments seg; - s->ctrl->reg_to_segment(s, regval, &seg); + asc->reg_to_segment(s, regval, &seg); memory_region_transaction_begin(); memory_region_set_size(&fl->mmio, seg.size); - memory_region_set_address(&fl->mmio, seg.addr - s->ctrl->flash_window_base); + memory_region_set_address(&fl->mmio, seg.addr - asc->flash_window_base); memory_region_set_enabled(&fl->mmio, !!seg.size); memory_region_transaction_commit(); @@ -546,53 +265,52 @@ static void aspeed_smc_flash_set_segment_region(AspeedSMCState *s, int cs, static void aspeed_smc_flash_set_segment(AspeedSMCState *s, int cs, uint64_t new) { + AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s); AspeedSegments seg; - s->ctrl->reg_to_segment(s, new, &seg); + asc->reg_to_segment(s, new, &seg); trace_aspeed_smc_flash_set_segment(cs, new, seg.addr, seg.addr + seg.size); /* The start address of CS0 is read-only */ - if (cs == 0 && seg.addr != s->ctrl->flash_window_base) { - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Tried to change CS0 start address to 0x%" - HWADDR_PRIx "\n", s->ctrl->name, seg.addr); - seg.addr = s->ctrl->flash_window_base; - new = s->ctrl->segment_to_reg(s, &seg); + if (cs == 0 && seg.addr != asc->flash_window_base) { + aspeed_smc_error("Tried to change CS0 start address to 0x%" + HWADDR_PRIx, seg.addr); + seg.addr = asc->flash_window_base; + new = asc->segment_to_reg(s, &seg); } /* * The end address of the AST2500 spi controllers is also * read-only. */ - if ((s->ctrl->segments == aspeed_segments_ast2500_spi1 || - s->ctrl->segments == aspeed_segments_ast2500_spi2) && - cs == s->ctrl->max_peripherals && - seg.addr + seg.size != s->ctrl->segments[cs].addr + - s->ctrl->segments[cs].size) { - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Tried to change CS%d end address to 0x%" - HWADDR_PRIx "\n", s->ctrl->name, cs, seg.addr + seg.size); - seg.size = s->ctrl->segments[cs].addr + s->ctrl->segments[cs].size - + if ((asc->segments == aspeed_2500_spi1_segments || + asc->segments == aspeed_2500_spi2_segments) && + cs == asc->max_peripherals && + seg.addr + seg.size != asc->segments[cs].addr + + asc->segments[cs].size) { + aspeed_smc_error("Tried to change CS%d end address to 0x%" + HWADDR_PRIx, cs, seg.addr + seg.size); + seg.size = asc->segments[cs].addr + asc->segments[cs].size - seg.addr; - new = s->ctrl->segment_to_reg(s, &seg); + new = asc->segment_to_reg(s, &seg); } /* Keep the segment in the overall flash window */ if (seg.size && - (seg.addr + seg.size <= s->ctrl->flash_window_base || - seg.addr > s->ctrl->flash_window_base + s->ctrl->flash_window_size)) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: new segment for CS%d is invalid : " - "[ 0x%"HWADDR_PRIx" - 0x%"HWADDR_PRIx" ]\n", - s->ctrl->name, cs, seg.addr, seg.addr + seg.size); + (seg.addr + seg.size <= asc->flash_window_base || + seg.addr > asc->flash_window_base + asc->flash_window_size)) { + aspeed_smc_error("new segment for CS%d is invalid : " + "[ 0x%"HWADDR_PRIx" - 0x%"HWADDR_PRIx" ]", + cs, seg.addr, seg.addr + seg.size); return; } /* Check start address vs. alignment */ if (seg.size && !QEMU_IS_ALIGNED(seg.addr, seg.size)) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: new segment for CS%d is not " - "aligned : [ 0x%"HWADDR_PRIx" - 0x%"HWADDR_PRIx" ]\n", - s->ctrl->name, cs, seg.addr, seg.addr + seg.size); + aspeed_smc_error("new segment for CS%d is not " + "aligned : [ 0x%"HWADDR_PRIx" - 0x%"HWADDR_PRIx" ]", + cs, seg.addr, seg.addr + seg.size); } /* And segments should not overlap (in the specs) */ @@ -605,16 +323,15 @@ static void aspeed_smc_flash_set_segment(AspeedSMCState *s, int cs, static uint64_t aspeed_smc_flash_default_read(void *opaque, hwaddr addr, unsigned size) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: To 0x%" HWADDR_PRIx " of size %u" - PRIx64 "\n", __func__, addr, size); + aspeed_smc_error("To 0x%" HWADDR_PRIx " of size %u" PRIx64, addr, size); return 0; } static void aspeed_smc_flash_default_write(void *opaque, hwaddr addr, uint64_t data, unsigned size) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: To 0x%" HWADDR_PRIx " of size %u: 0x%" - PRIx64 "\n", __func__, addr, size, data); + aspeed_smc_error("To 0x%" HWADDR_PRIx " of size %u: 0x%" PRIx64, + addr, size, data); } static const MemoryRegionOps aspeed_smc_flash_default_ops = { @@ -631,20 +348,20 @@ static inline int aspeed_smc_flash_mode(const AspeedSMCFlash *fl) { const AspeedSMCState *s = fl->controller; - return s->regs[s->r_ctrl0 + fl->id] & CTRL_CMD_MODE_MASK; + return s->regs[s->r_ctrl0 + fl->cs] & CTRL_CMD_MODE_MASK; } static inline bool aspeed_smc_is_writable(const AspeedSMCFlash *fl) { const AspeedSMCState *s = fl->controller; - return s->regs[s->r_conf] & (1 << (s->conf_enable_w0 + fl->id)); + return s->regs[s->r_conf] & (1 << (s->conf_enable_w0 + fl->cs)); } static inline int aspeed_smc_flash_cmd(const AspeedSMCFlash *fl) { const AspeedSMCState *s = fl->controller; - int cmd = (s->regs[s->r_ctrl0 + fl->id] >> CTRL_CMD_SHIFT) & CTRL_CMD_MASK; + int cmd = (s->regs[s->r_ctrl0 + fl->cs] >> CTRL_CMD_SHIFT) & CTRL_CMD_MASK; /* * In read mode, the default SPI command is READ (0x3). In other @@ -657,21 +374,22 @@ static inline int aspeed_smc_flash_cmd(const AspeedSMCFlash *fl) } if (!cmd) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: no command defined for mode %d\n", - __func__, aspeed_smc_flash_mode(fl)); + aspeed_smc_error("no command defined for mode %d", + aspeed_smc_flash_mode(fl)); } return cmd; } -static inline int aspeed_smc_flash_is_4byte(const AspeedSMCFlash *fl) +static inline int aspeed_smc_flash_addr_width(const AspeedSMCFlash *fl) { const AspeedSMCState *s = fl->controller; + AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s); - if (s->ctrl->segments == aspeed_segments_spi) { - return s->regs[s->r_ctrl0] & CTRL_AST2400_SPI_4BYTE; + if (asc->addr_width) { + return asc->addr_width(s); } else { - return s->regs[s->r_ce_ctrl] & (1 << (CTRL_EXTENDED0 + fl->id)); + return s->regs[s->r_ce_ctrl] & (1 << (CTRL_EXTENDED0 + fl->cs)) ? 4 : 3; } } @@ -679,9 +397,9 @@ static void aspeed_smc_flash_do_select(AspeedSMCFlash *fl, bool unselect) { AspeedSMCState *s = fl->controller; - trace_aspeed_smc_flash_select(fl->id, unselect ? "un" : ""); + trace_aspeed_smc_flash_select(fl->cs, unselect ? "un" : ""); - qemu_set_irq(s->cs_lines[fl->id], unselect); + qemu_set_irq(s->cs_lines[fl->cs], unselect); } static void aspeed_smc_flash_select(AspeedSMCFlash *fl) @@ -698,15 +416,14 @@ static uint32_t aspeed_smc_check_segment_addr(const AspeedSMCFlash *fl, uint32_t addr) { const AspeedSMCState *s = fl->controller; + AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s); AspeedSegments seg; - s->ctrl->reg_to_segment(s, s->regs[R_SEG_ADDR0 + fl->id], &seg); + asc->reg_to_segment(s, s->regs[R_SEG_ADDR0 + fl->cs], &seg); if ((addr % seg.size) != addr) { - qemu_log_mask(LOG_GUEST_ERROR, - "%s: invalid address 0x%08x for CS%d segment : " - "[ 0x%"HWADDR_PRIx" - 0x%"HWADDR_PRIx" ]\n", - s->ctrl->name, addr, fl->id, seg.addr, - seg.addr + seg.size); + aspeed_smc_error("invalid address 0x%08x for CS%d segment : " + "[ 0x%"HWADDR_PRIx" - 0x%"HWADDR_PRIx" ]", + addr, fl->cs, seg.addr, seg.addr + seg.size); addr %= seg.size; } @@ -716,7 +433,7 @@ static uint32_t aspeed_smc_check_segment_addr(const AspeedSMCFlash *fl, static int aspeed_smc_flash_dummies(const AspeedSMCFlash *fl) { const AspeedSMCState *s = fl->controller; - uint32_t r_ctrl0 = s->regs[s->r_ctrl0 + fl->id]; + uint32_t r_ctrl0 = s->regs[s->r_ctrl0 + fl->cs]; uint32_t dummy_high = (r_ctrl0 >> CTRL_DUMMY_HIGH_SHIFT) & 0x1; uint32_t dummy_low = (r_ctrl0 >> CTRL_DUMMY_LOW_SHIFT) & 0x3; uint32_t dummies = ((dummy_high << 2) | dummy_low) * 8; @@ -732,7 +449,7 @@ static void aspeed_smc_flash_setup(AspeedSMCFlash *fl, uint32_t addr) { const AspeedSMCState *s = fl->controller; uint8_t cmd = aspeed_smc_flash_cmd(fl); - int i = aspeed_smc_flash_is_4byte(fl) ? 4 : 3; + int i = aspeed_smc_flash_addr_width(fl); /* Flash access can not exceed CS segment */ addr = aspeed_smc_check_segment_addr(fl, addr); @@ -782,11 +499,10 @@ static uint64_t aspeed_smc_flash_read(void *opaque, hwaddr addr, unsigned size) aspeed_smc_flash_unselect(fl); break; default: - qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid flash mode %d\n", - __func__, aspeed_smc_flash_mode(fl)); + aspeed_smc_error("invalid flash mode %d", aspeed_smc_flash_mode(fl)); } - trace_aspeed_smc_flash_read(fl->id, addr, size, ret, + trace_aspeed_smc_flash_read(fl->cs, addr, size, ret, aspeed_smc_flash_mode(fl)); return ret; } @@ -841,9 +557,9 @@ static bool aspeed_smc_do_snoop(AspeedSMCFlash *fl, uint64_t data, unsigned size) { AspeedSMCState *s = fl->controller; - uint8_t addr_width = aspeed_smc_flash_is_4byte(fl) ? 4 : 3; + uint8_t addr_width = aspeed_smc_flash_addr_width(fl); - trace_aspeed_smc_do_snoop(fl->id, s->snoop_index, s->snoop_dummies, + trace_aspeed_smc_do_snoop(fl->cs, s->snoop_index, s->snoop_dummies, (uint8_t) data & 0xff); if (s->snoop_index == SNOOP_OFF) { @@ -896,12 +612,11 @@ static void aspeed_smc_flash_write(void *opaque, hwaddr addr, uint64_t data, AspeedSMCState *s = fl->controller; int i; - trace_aspeed_smc_flash_write(fl->id, addr, size, data, + trace_aspeed_smc_flash_write(fl->cs, addr, size, data, aspeed_smc_flash_mode(fl)); if (!aspeed_smc_is_writable(fl)) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: flash is not writable at 0x%" - HWADDR_PRIx "\n", __func__, addr); + aspeed_smc_error("flash is not writable at 0x%" HWADDR_PRIx, addr); return; } @@ -926,8 +641,7 @@ static void aspeed_smc_flash_write(void *opaque, hwaddr addr, uint64_t data, aspeed_smc_flash_unselect(fl); break; default: - qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid flash mode %d\n", - __func__, aspeed_smc_flash_mode(fl)); + aspeed_smc_error("invalid flash mode %d", aspeed_smc_flash_mode(fl)); } } @@ -950,12 +664,12 @@ static void aspeed_smc_flash_update_ctrl(AspeedSMCFlash *fl, uint32_t value) unselect = (value & CTRL_CMD_MODE_MASK) != CTRL_USERMODE; /* A change of CTRL_CE_STOP_ACTIVE from 0 to 1, unselects the CS */ - if (!(s->regs[s->r_ctrl0 + fl->id] & CTRL_CE_STOP_ACTIVE) && + if (!(s->regs[s->r_ctrl0 + fl->cs] & CTRL_CE_STOP_ACTIVE) && value & CTRL_CE_STOP_ACTIVE) { unselect = true; } - s->regs[s->r_ctrl0 + fl->id] = value; + s->regs[s->r_ctrl0 + fl->cs] = value; s->snoop_index = unselect ? SNOOP_OFF : SNOOP_START; @@ -965,9 +679,14 @@ static void aspeed_smc_flash_update_ctrl(AspeedSMCFlash *fl, uint32_t value) static void aspeed_smc_reset(DeviceState *d) { AspeedSMCState *s = ASPEED_SMC(d); + AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s); int i; - memset(s->regs, 0, sizeof s->regs); + if (asc->resets) { + memcpy(s->regs, asc->resets, sizeof s->regs); + } else { + memset(s->regs, 0, sizeof s->regs); + } /* Unselect all peripherals */ for (i = 0; i < s->num_cs; ++i) { @@ -976,30 +695,9 @@ static void aspeed_smc_reset(DeviceState *d) } /* setup the default segment register values and regions for all */ - for (i = 0; i < s->ctrl->max_peripherals; ++i) { + for (i = 0; i < asc->max_peripherals; ++i) { aspeed_smc_flash_set_segment_region(s, i, - s->ctrl->segment_to_reg(s, &s->ctrl->segments[i])); - } - - /* HW strapping flash type for the AST2600 controllers */ - if (s->ctrl->segments == aspeed_segments_ast2600_fmc) { - /* flash type is fixed to SPI for all */ - s->regs[s->r_conf] |= (CONF_FLASH_TYPE_SPI << CONF_FLASH_TYPE0); - s->regs[s->r_conf] |= (CONF_FLASH_TYPE_SPI << CONF_FLASH_TYPE1); - s->regs[s->r_conf] |= (CONF_FLASH_TYPE_SPI << CONF_FLASH_TYPE2); - } - - /* HW strapping flash type for FMC controllers */ - if (s->ctrl->segments == aspeed_segments_ast2500_fmc) { - /* flash type is fixed to SPI for CE0 and CE1 */ - s->regs[s->r_conf] |= (CONF_FLASH_TYPE_SPI << CONF_FLASH_TYPE0); - s->regs[s->r_conf] |= (CONF_FLASH_TYPE_SPI << CONF_FLASH_TYPE1); - } - - /* HW strapping for AST2400 FMC controllers (SCU70). Let's use the - * configuration of the palmetto-bmc machine */ - if (s->ctrl->segments == aspeed_segments_fmc) { - s->regs[s->r_conf] |= (CONF_FLASH_TYPE_SPI << CONF_FLASH_TYPE0); + asc->segment_to_reg(s, &asc->segments[i])); } s->snoop_index = SNOOP_OFF; @@ -1009,26 +707,28 @@ static void aspeed_smc_reset(DeviceState *d) static uint64_t aspeed_smc_read(void *opaque, hwaddr addr, unsigned int size) { AspeedSMCState *s = ASPEED_SMC(opaque); + AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(opaque); addr >>= 2; if (addr == s->r_conf || (addr >= s->r_timings && - addr < s->r_timings + s->ctrl->nregs_timings) || + addr < s->r_timings + asc->nregs_timings) || addr == s->r_ce_ctrl || addr == R_CE_CMD_CTRL || addr == R_INTR_CTRL || addr == R_DUMMY_DATA || - (aspeed_smc_has_dma(s) && addr == R_DMA_CTRL) || - (aspeed_smc_has_dma(s) && addr == R_DMA_FLASH_ADDR) || - (aspeed_smc_has_dma(s) && addr == R_DMA_DRAM_ADDR) || - (aspeed_smc_has_dma(s) && addr == R_DMA_LEN) || - (aspeed_smc_has_dma(s) && addr == R_DMA_CHECKSUM) || + (aspeed_smc_has_wdt_control(asc) && addr == R_FMC_WDT2_CTRL) || + (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) && addr == R_DMA_LEN) || + (aspeed_smc_has_dma(asc) && addr == R_DMA_CHECKSUM) || (addr >= R_SEG_ADDR0 && - addr < R_SEG_ADDR0 + s->ctrl->max_peripherals) || - (addr >= s->r_ctrl0 && addr < s->r_ctrl0 + s->ctrl->max_peripherals)) { + addr < R_SEG_ADDR0 + asc->max_peripherals) || + (addr >= s->r_ctrl0 && addr < s->r_ctrl0 + asc->max_peripherals)) { - trace_aspeed_smc_read(addr, size, s->regs[addr]); + trace_aspeed_smc_read(addr << 2, size, s->regs[addr]); return s->regs[addr]; } else { @@ -1052,7 +752,7 @@ static uint8_t aspeed_smc_hclk_divisor(uint8_t hclk_mask) } } - qemu_log_mask(LOG_GUEST_ERROR, "invalid HCLK mask %x", hclk_mask); + aspeed_smc_error("invalid HCLK mask %x", hclk_mask); return 0; } @@ -1132,8 +832,7 @@ static void aspeed_smc_dma_checksum(AspeedSMCState *s) uint32_t data; if (s->regs[R_DMA_CTRL] & DMA_CTRL_WRITE) { - qemu_log_mask(LOG_GUEST_ERROR, - "%s: invalid direction for DMA checksum\n", __func__); + aspeed_smc_error("invalid direction for DMA checksum"); return; } @@ -1145,8 +844,8 @@ static void aspeed_smc_dma_checksum(AspeedSMCState *s) data = address_space_ldl_le(&s->flash_as, s->regs[R_DMA_FLASH_ADDR], MEMTXATTRS_UNSPECIFIED, &result); if (result != MEMTX_OK) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: Flash read failed @%08x\n", - __func__, s->regs[R_DMA_FLASH_ADDR]); + aspeed_smc_error("Flash read failed @%08x", + s->regs[R_DMA_FLASH_ADDR]); return; } trace_aspeed_smc_dma_checksum(s->regs[R_DMA_FLASH_ADDR], data); @@ -1181,32 +880,32 @@ static void aspeed_smc_dma_rw(AspeedSMCState *s) data = address_space_ldl_le(&s->dram_as, s->regs[R_DMA_DRAM_ADDR], MEMTXATTRS_UNSPECIFIED, &result); if (result != MEMTX_OK) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: DRAM read failed @%08x\n", - __func__, s->regs[R_DMA_DRAM_ADDR]); + aspeed_smc_error("DRAM read failed @%08x", + s->regs[R_DMA_DRAM_ADDR]); return; } address_space_stl_le(&s->flash_as, s->regs[R_DMA_FLASH_ADDR], data, MEMTXATTRS_UNSPECIFIED, &result); if (result != MEMTX_OK) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: Flash write failed @%08x\n", - __func__, s->regs[R_DMA_FLASH_ADDR]); + aspeed_smc_error("Flash write failed @%08x", + s->regs[R_DMA_FLASH_ADDR]); return; } } else { data = address_space_ldl_le(&s->flash_as, s->regs[R_DMA_FLASH_ADDR], MEMTXATTRS_UNSPECIFIED, &result); if (result != MEMTX_OK) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: Flash read failed @%08x\n", - __func__, s->regs[R_DMA_FLASH_ADDR]); + aspeed_smc_error("Flash read failed @%08x", + s->regs[R_DMA_FLASH_ADDR]); return; } address_space_stl_le(&s->dram_as, s->regs[R_DMA_DRAM_ADDR], data, MEMTXATTRS_UNSPECIFIED, &result); if (result != MEMTX_OK) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: DRAM write failed @%08x\n", - __func__, s->regs[R_DMA_DRAM_ADDR]); + aspeed_smc_error("DRAM write failed @%08x", + s->regs[R_DMA_DRAM_ADDR]); return; } } @@ -1266,7 +965,7 @@ static void aspeed_smc_dma_ctrl(AspeedSMCState *s, uint32_t dma_ctrl) } if (aspeed_smc_dma_in_progress(s)) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: DMA in progress\n", __func__); + aspeed_smc_error("DMA in progress !"); return; } @@ -1283,12 +982,14 @@ static void aspeed_smc_dma_ctrl(AspeedSMCState *s, uint32_t dma_ctrl) static inline bool aspeed_smc_dma_granted(AspeedSMCState *s) { - if (!(s->ctrl->features & ASPEED_SMC_FEATURE_DMA_GRANT)) { + AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s); + + if (!(asc->features & ASPEED_SMC_FEATURE_DMA_GRANT)) { return true; } if (!(s->regs[R_DMA_CTRL] & DMA_CTRL_GRANT)) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: DMA not granted\n", __func__); + aspeed_smc_error("DMA not granted"); return false; } @@ -1313,7 +1014,7 @@ static void aspeed_2600_smc_dma_ctrl(AspeedSMCState *s, uint32_t dma_ctrl) } if (!aspeed_smc_dma_granted(s)) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: DMA not granted\n", __func__); + aspeed_smc_error("DMA not granted"); return; } @@ -1325,22 +1026,23 @@ static void aspeed_smc_write(void *opaque, hwaddr addr, uint64_t data, unsigned int size) { AspeedSMCState *s = ASPEED_SMC(opaque); + AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s); uint32_t value = data; - addr >>= 2; - trace_aspeed_smc_write(addr, size, data); + addr >>= 2; + if (addr == s->r_conf || (addr >= s->r_timings && - addr < s->r_timings + s->ctrl->nregs_timings) || + addr < s->r_timings + asc->nregs_timings) || addr == s->r_ce_ctrl) { s->regs[addr] = value; } else if (addr >= s->r_ctrl0 && addr < s->r_ctrl0 + s->num_cs) { int cs = addr - s->r_ctrl0; aspeed_smc_flash_update_ctrl(&s->flashes[cs], value); } else if (addr >= R_SEG_ADDR0 && - addr < R_SEG_ADDR0 + s->ctrl->max_peripherals) { + addr < R_SEG_ADDR0 + asc->max_peripherals) { int cs = addr - R_SEG_ADDR0; if (value != s->regs[R_SEG_ADDR0 + cs]) { @@ -1350,17 +1052,19 @@ static void aspeed_smc_write(void *opaque, hwaddr addr, uint64_t data, s->regs[addr] = value & 0xff; } else if (addr == R_DUMMY_DATA) { s->regs[addr] = value & 0xff; + } else if (aspeed_smc_has_wdt_control(asc) && addr == R_FMC_WDT2_CTRL) { + s->regs[addr] = value & FMC_WDT2_CTRL_EN; } else if (addr == R_INTR_CTRL) { s->regs[addr] = value; - } else if (aspeed_smc_has_dma(s) && addr == R_DMA_CTRL) { - s->ctrl->dma_ctrl(s, value); - } else if (aspeed_smc_has_dma(s) && addr == R_DMA_DRAM_ADDR && + } else if (aspeed_smc_has_dma(asc) && addr == R_DMA_CTRL) { + asc->dma_ctrl(s, value); + } else if (aspeed_smc_has_dma(asc) && addr == R_DMA_DRAM_ADDR && aspeed_smc_dma_granted(s)) { - s->regs[addr] = DMA_DRAM_ADDR(s, value); - } else if (aspeed_smc_has_dma(s) && addr == R_DMA_FLASH_ADDR && + s->regs[addr] = DMA_DRAM_ADDR(asc, value); + } else if (aspeed_smc_has_dma(asc) && addr == R_DMA_FLASH_ADDR && aspeed_smc_dma_granted(s)) { - s->regs[addr] = DMA_FLASH_ADDR(s, value); - } else if (aspeed_smc_has_dma(s) && addr == R_DMA_LEN && + s->regs[addr] = DMA_FLASH_ADDR(asc, value); + } else if (aspeed_smc_has_dma(asc) && addr == R_DMA_LEN && aspeed_smc_dma_granted(s)) { s->regs[addr] = DMA_LENGTH(value); } else { @@ -1376,50 +1080,53 @@ static const MemoryRegionOps aspeed_smc_ops = { .endianness = DEVICE_LITTLE_ENDIAN, }; +static void aspeed_smc_instance_init(Object *obj) +{ + AspeedSMCState *s = ASPEED_SMC(obj); + AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s); + int i; + + for (i = 0; i < asc->max_peripherals; i++) { + object_initialize_child(obj, "flash[*]", &s->flashes[i], + TYPE_ASPEED_SMC_FLASH); + } +} + /* * Initialize the custom address spaces for DMAs */ static void aspeed_smc_dma_setup(AspeedSMCState *s, Error **errp) { - char *name; - if (!s->dram_mr) { error_setg(errp, TYPE_ASPEED_SMC ": 'dram' link not set"); return; } - name = g_strdup_printf("%s-dma-flash", s->ctrl->name); - address_space_init(&s->flash_as, &s->mmio_flash, name); - g_free(name); - - name = g_strdup_printf("%s-dma-dram", s->ctrl->name); - address_space_init(&s->dram_as, s->dram_mr, name); - g_free(name); + address_space_init(&s->flash_as, &s->mmio_flash, + TYPE_ASPEED_SMC ".dma-flash"); + address_space_init(&s->dram_as, s->dram_mr, + TYPE_ASPEED_SMC ".dma-dram"); } static void aspeed_smc_realize(DeviceState *dev, Error **errp) { SysBusDevice *sbd = SYS_BUS_DEVICE(dev); AspeedSMCState *s = ASPEED_SMC(dev); - AspeedSMCClass *mc = ASPEED_SMC_GET_CLASS(s); + AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s); int i; - char name[32]; hwaddr offset = 0; - s->ctrl = mc->ctrl; - /* keep a copy under AspeedSMCState to speed up accesses */ - s->r_conf = s->ctrl->r_conf; - s->r_ce_ctrl = s->ctrl->r_ce_ctrl; - s->r_ctrl0 = s->ctrl->r_ctrl0; - s->r_timings = s->ctrl->r_timings; - s->conf_enable_w0 = s->ctrl->conf_enable_w0; + s->r_conf = asc->r_conf; + s->r_ce_ctrl = asc->r_ce_ctrl; + s->r_ctrl0 = asc->r_ctrl0; + s->r_timings = asc->r_timings; + s->conf_enable_w0 = asc->conf_enable_w0; /* Enforce some real HW limits */ - if (s->num_cs > s->ctrl->max_peripherals) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: num_cs cannot exceed: %d\n", - __func__, s->ctrl->max_peripherals); - s->num_cs = s->ctrl->max_peripherals; + if (s->num_cs > asc->max_peripherals) { + aspeed_smc_error("num_cs cannot exceed: %d", asc->max_peripherals); + s->num_cs = asc->max_peripherals; } /* DMA irq. Keep it first for the initialization in the SoC */ @@ -1436,7 +1143,7 @@ static void aspeed_smc_realize(DeviceState *dev, Error **errp) /* The memory region for the controller registers */ memory_region_init_io(&s->mmio, OBJECT(s), &aspeed_smc_ops, s, - s->ctrl->name, s->ctrl->nregs * 4); + TYPE_ASPEED_SMC, asc->nregs * 4); sysbus_init_mmio(sbd, &s->mmio); /* @@ -1444,17 +1151,15 @@ static void aspeed_smc_realize(DeviceState *dev, Error **errp) * window in which the flash modules are mapped. The size and * address depends on the SoC model and controller type. */ - snprintf(name, sizeof(name), "%s.flash", s->ctrl->name); - memory_region_init_io(&s->mmio_flash, OBJECT(s), - &aspeed_smc_flash_default_ops, s, name, - s->ctrl->flash_window_size); - memory_region_init_alias(&s->mmio_flash_alias, OBJECT(s), name, - &s->mmio_flash, 0, s->ctrl->flash_window_size); + &aspeed_smc_flash_default_ops, s, + TYPE_ASPEED_SMC ".flash", + asc->flash_window_size); + memory_region_init_alias(&s->mmio_flash_alias, OBJECT(s), + TYPE_ASPEED_SMC ".flash", + &s->mmio_flash, 0, asc->flash_window_size); sysbus_init_mmio(sbd, &s->mmio_flash_alias); - s->flashes = g_new0(AspeedSMCFlash, s->ctrl->max_peripherals); - /* * Let's create a sub memory region for each possible peripheral. All * have a configurable memory segment in the overall flash mapping @@ -1462,22 +1167,26 @@ static void aspeed_smc_realize(DeviceState *dev, Error **errp) * module behind to handle the memory accesses. This depends on * the board configuration. */ - for (i = 0; i < s->ctrl->max_peripherals; ++i) { + for (i = 0; i < asc->max_peripherals; ++i) { AspeedSMCFlash *fl = &s->flashes[i]; - snprintf(name, sizeof(name), "%s.%d", s->ctrl->name, i); + if (!object_property_set_link(OBJECT(fl), "controller", OBJECT(s), + errp)) { + return; + } + if (!object_property_set_uint(OBJECT(fl), "cs", i, errp)) { + return; + } + if (!sysbus_realize(SYS_BUS_DEVICE(fl), errp)) { + return; + } - fl->id = i; - fl->controller = s; - fl->size = s->ctrl->segments[i].size; - memory_region_init_io(&fl->mmio, OBJECT(s), &aspeed_smc_flash_ops, - fl, name, fl->size); memory_region_add_subregion(&s->mmio_flash, offset, &fl->mmio); - offset += fl->size; + offset += asc->segments[i].size; } /* DMA support */ - if (aspeed_smc_has_dma(s)) { + if (aspeed_smc_has_dma(asc)) { aspeed_smc_dma_setup(s, errp); } } @@ -1505,37 +1214,494 @@ static Property aspeed_smc_properties[] = { static void aspeed_smc_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - AspeedSMCClass *mc = ASPEED_SMC_CLASS(klass); dc->realize = aspeed_smc_realize; dc->reset = aspeed_smc_reset; device_class_set_props(dc, aspeed_smc_properties); dc->vmsd = &vmstate_aspeed_smc; - mc->ctrl = data; } static const TypeInfo aspeed_smc_info = { .name = TYPE_ASPEED_SMC, .parent = TYPE_SYS_BUS_DEVICE, + .instance_init = aspeed_smc_instance_init, .instance_size = sizeof(AspeedSMCState), .class_size = sizeof(AspeedSMCClass), + .class_init = aspeed_smc_class_init, .abstract = true, }; +static void aspeed_smc_flash_realize(DeviceState *dev, Error **errp) +{ + AspeedSMCFlash *s = ASPEED_SMC_FLASH(dev); + AspeedSMCClass *asc; + g_autofree char *name = g_strdup_printf(TYPE_ASPEED_SMC_FLASH ".%d", s->cs); + + if (!s->controller) { + error_setg(errp, TYPE_ASPEED_SMC_FLASH ": 'controller' link not set"); + return; + } + + asc = ASPEED_SMC_GET_CLASS(s->controller); + + /* + * 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, + s, name, asc->segments[s->cs].size); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio); +} + +static Property aspeed_smc_flash_properties[] = { + DEFINE_PROP_UINT8("cs", AspeedSMCFlash, cs, 0), + DEFINE_PROP_LINK("controller", AspeedSMCFlash, controller, TYPE_ASPEED_SMC, + AspeedSMCState *), + DEFINE_PROP_END_OF_LIST(), +}; + +static void aspeed_smc_flash_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->desc = "Aspeed SMC Flash device region"; + dc->realize = aspeed_smc_flash_realize; + device_class_set_props(dc, aspeed_smc_flash_properties); +} + +static const TypeInfo aspeed_smc_flash_info = { + .name = TYPE_ASPEED_SMC_FLASH, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(AspeedSMCFlash), + .class_init = aspeed_smc_flash_class_init, +}; + +/* + * The Segment Registers of the AST2400 and AST2500 have a 8MB + * unit. The address range of a flash SPI peripheral is encoded with + * absolute addresses which should be part of the overall controller + * window. + */ +static uint32_t aspeed_smc_segment_to_reg(const AspeedSMCState *s, + const AspeedSegments *seg) +{ + uint32_t reg = 0; + reg |= ((seg->addr >> 23) & SEG_START_MASK) << SEG_START_SHIFT; + reg |= (((seg->addr + seg->size) >> 23) & SEG_END_MASK) << SEG_END_SHIFT; + return reg; +} + +static void aspeed_smc_reg_to_segment(const AspeedSMCState *s, + uint32_t reg, AspeedSegments *seg) +{ + seg->addr = ((reg >> SEG_START_SHIFT) & SEG_START_MASK) << 23; + seg->size = (((reg >> SEG_END_SHIFT) & SEG_END_MASK) << 23) - seg->addr; +} + +static const AspeedSegments aspeed_2400_smc_segments[] = { + { 0x10000000, 32 * MiB }, +}; + +static void aspeed_2400_smc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass); + + dc->desc = "Aspeed 2400 SMC 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 = 1; + asc->conf_enable_w0 = CONF_ENABLE_W0; + asc->max_peripherals = 1; + asc->segments = aspeed_2400_smc_segments; + asc->flash_window_base = 0x10000000; + asc->flash_window_size = 0x6000000; + asc->features = 0x0; + asc->nregs = ASPEED_SMC_R_SMC_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; +} + +static const TypeInfo aspeed_2400_smc_info = { + .name = "aspeed.smc-ast2400", + .parent = TYPE_ASPEED_SMC, + .class_init = aspeed_2400_smc_class_init, +}; + +static const uint32_t aspeed_2400_fmc_resets[ASPEED_SMC_R_MAX] = { + /* + * CE0 and CE1 types are HW strapped in SCU70. Do it here to + * simplify the model. + */ + [R_CONF] = CONF_FLASH_TYPE_SPI << CONF_FLASH_TYPE0, +}; + +static const AspeedSegments aspeed_2400_fmc_segments[] = { + { 0x20000000, 64 * MiB }, /* start address is readonly */ + { 0x24000000, 32 * MiB }, + { 0x26000000, 32 * MiB }, + { 0x28000000, 32 * MiB }, + { 0x2A000000, 32 * MiB } +}; + +static void aspeed_2400_fmc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass); + + dc->desc = "Aspeed 2400 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 = 1; + asc->conf_enable_w0 = CONF_ENABLE_W0; + asc->max_peripherals = 5; + asc->segments = aspeed_2400_fmc_segments; + asc->resets = aspeed_2400_fmc_resets; + asc->flash_window_base = 0x20000000; + asc->flash_window_size = 0x10000000; + asc->features = ASPEED_SMC_FEATURE_DMA; + asc->dma_flash_mask = 0x0FFFFFFC; + asc->dma_dram_mask = 0x1FFFFFFC; + 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; +} + +static const TypeInfo aspeed_2400_fmc_info = { + .name = "aspeed.fmc-ast2400", + .parent = TYPE_ASPEED_SMC, + .class_init = aspeed_2400_fmc_class_init, +}; + +static const AspeedSegments aspeed_2400_spi1_segments[] = { + { 0x30000000, 64 * MiB }, +}; + +static int aspeed_2400_spi1_addr_width(const AspeedSMCState *s) +{ + return s->regs[R_SPI_CTRL0] & CTRL_AST2400_SPI_4BYTE ? 4 : 3; +} + +static void aspeed_2400_spi1_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass); + + dc->desc = "Aspeed 2400 SPI1 Controller"; + asc->r_conf = R_SPI_CONF; + asc->r_ce_ctrl = 0xff; + asc->r_ctrl0 = R_SPI_CTRL0; + asc->r_timings = R_SPI_TIMINGS; + asc->nregs_timings = 1; + asc->conf_enable_w0 = SPI_CONF_ENABLE_W0; + asc->max_peripherals = 1; + asc->segments = aspeed_2400_spi1_segments; + asc->flash_window_base = 0x30000000; + asc->flash_window_size = 0x10000000; + asc->features = 0x0; + asc->nregs = ASPEED_SMC_R_SPI_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->addr_width = aspeed_2400_spi1_addr_width; +} + +static const TypeInfo aspeed_2400_spi1_info = { + .name = "aspeed.spi1-ast2400", + .parent = TYPE_ASPEED_SMC, + .class_init = aspeed_2400_spi1_class_init, +}; + +static const uint32_t aspeed_2500_fmc_resets[ASPEED_SMC_R_MAX] = { + [R_CONF] = (CONF_FLASH_TYPE_SPI << CONF_FLASH_TYPE0 | + CONF_FLASH_TYPE_SPI << CONF_FLASH_TYPE1), +}; + +static const AspeedSegments aspeed_2500_fmc_segments[] = { + { 0x20000000, 128 * MiB }, /* start address is readonly */ + { 0x28000000, 32 * MiB }, + { 0x2A000000, 32 * MiB }, +}; + +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"; + 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 = 1; + asc->conf_enable_w0 = CONF_ENABLE_W0; + asc->max_peripherals = 3; + asc->segments = aspeed_2500_fmc_segments; + asc->resets = aspeed_2500_fmc_resets; + asc->flash_window_base = 0x20000000; + asc->flash_window_size = 0x10000000; + asc->features = ASPEED_SMC_FEATURE_DMA; + asc->dma_flash_mask = 0x0FFFFFFC; + asc->dma_dram_mask = 0x3FFFFFFC; + 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; +} + +static const TypeInfo aspeed_2500_fmc_info = { + .name = "aspeed.fmc-ast2500", + .parent = TYPE_ASPEED_SMC, + .class_init = aspeed_2500_fmc_class_init, +}; + +static const AspeedSegments aspeed_2500_spi1_segments[] = { + { 0x30000000, 32 * MiB }, /* start address is readonly */ + { 0x32000000, 96 * MiB }, /* end address is readonly */ +}; + +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"; + 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 = 1; + asc->conf_enable_w0 = CONF_ENABLE_W0; + asc->max_peripherals = 2; + asc->segments = aspeed_2500_spi1_segments; + asc->flash_window_base = 0x30000000; + asc->flash_window_size = 0x8000000; + asc->features = 0x0; + 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; +} + +static const TypeInfo aspeed_2500_spi1_info = { + .name = "aspeed.spi1-ast2500", + .parent = TYPE_ASPEED_SMC, + .class_init = aspeed_2500_spi1_class_init, +}; + +static const AspeedSegments aspeed_2500_spi2_segments[] = { + { 0x38000000, 32 * MiB }, /* start address is readonly */ + { 0x3A000000, 96 * MiB }, /* end address is readonly */ +}; + +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"; + 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 = 1; + asc->conf_enable_w0 = CONF_ENABLE_W0; + asc->max_peripherals = 2; + asc->segments = aspeed_2500_spi2_segments; + asc->flash_window_base = 0x38000000; + asc->flash_window_size = 0x8000000; + asc->features = 0x0; + 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; +} + +static const TypeInfo aspeed_2500_spi2_info = { + .name = "aspeed.spi2-ast2500", + .parent = TYPE_ASPEED_SMC, + .class_init = aspeed_2500_spi2_class_init, +}; + +/* + * The Segment Registers of the AST2600 have a 1MB unit. The address + * range of a flash SPI peripheral is encoded with offsets in the overall + * controller window. The previous SoC AST2400 and AST2500 used + * absolute addresses. Only bits [27:20] are relevant and the end + * address is an upper bound limit. + */ +#define AST2600_SEG_ADDR_MASK 0x0ff00000 + +static uint32_t aspeed_2600_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 & AST2600_SEG_ADDR_MASK) >> 16; /* start offset */ + reg |= (seg->addr + seg->size - 1) & AST2600_SEG_ADDR_MASK; /* end offset */ + return reg; +} + +static void aspeed_2600_smc_reg_to_segment(const AspeedSMCState *s, + uint32_t reg, AspeedSegments *seg) +{ + uint32_t start_offset = (reg << 16) & AST2600_SEG_ADDR_MASK; + uint32_t end_offset = reg & AST2600_SEG_ADDR_MASK; + AspeedSMCClass *asc = ASPEED_SMC_GET_CLASS(s); + + if (reg) { + seg->addr = asc->flash_window_base + start_offset; + seg->size = end_offset + MiB - start_offset; + } else { + seg->addr = asc->flash_window_base; + seg->size = 0; + } +} + +static const uint32_t aspeed_2600_fmc_resets[ASPEED_SMC_R_MAX] = { + [R_CONF] = (CONF_FLASH_TYPE_SPI << CONF_FLASH_TYPE0 | + CONF_FLASH_TYPE_SPI << CONF_FLASH_TYPE1 | + CONF_FLASH_TYPE_SPI << CONF_FLASH_TYPE2), +}; + +static const AspeedSegments aspeed_2600_fmc_segments[] = { + { 0x0, 128 * MiB }, /* start address is readonly */ + { 128 * MiB, 128 * MiB }, /* default is disabled but needed for -kernel */ + { 0x0, 0 }, /* disabled */ +}; + +static void aspeed_2600_fmc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass); + + dc->desc = "Aspeed 2600 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 = 1; + asc->conf_enable_w0 = CONF_ENABLE_W0; + asc->max_peripherals = 3; + asc->segments = aspeed_2600_fmc_segments; + asc->resets = aspeed_2600_fmc_resets; + asc->flash_window_base = 0x20000000; + asc->flash_window_size = 0x10000000; + asc->features = ASPEED_SMC_FEATURE_DMA | + ASPEED_SMC_FEATURE_WDT_CONTROL; + asc->dma_flash_mask = 0x0FFFFFFC; + asc->dma_dram_mask = 0x3FFFFFFC; + 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; +} + +static const TypeInfo aspeed_2600_fmc_info = { + .name = "aspeed.fmc-ast2600", + .parent = TYPE_ASPEED_SMC, + .class_init = aspeed_2600_fmc_class_init, +}; + +static const AspeedSegments aspeed_2600_spi1_segments[] = { + { 0x0, 128 * MiB }, /* start address is readonly */ + { 0x0, 0 }, /* disabled */ +}; + +static void aspeed_2600_spi1_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass); + + dc->desc = "Aspeed 2600 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->max_peripherals = 2; + asc->segments = aspeed_2600_spi1_segments; + asc->flash_window_base = 0x30000000; + asc->flash_window_size = 0x10000000; + asc->features = ASPEED_SMC_FEATURE_DMA | + ASPEED_SMC_FEATURE_DMA_GRANT; + asc->dma_flash_mask = 0x0FFFFFFC; + asc->dma_dram_mask = 0x3FFFFFFC; + 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; +} + +static const TypeInfo aspeed_2600_spi1_info = { + .name = "aspeed.spi1-ast2600", + .parent = TYPE_ASPEED_SMC, + .class_init = aspeed_2600_spi1_class_init, +}; + +static const AspeedSegments aspeed_2600_spi2_segments[] = { + { 0x0, 128 * MiB }, /* start address is readonly */ + { 0x0, 0 }, /* disabled */ + { 0x0, 0 }, /* disabled */ +}; + +static void aspeed_2600_spi2_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass); + + dc->desc = "Aspeed 2600 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 = 3; + asc->conf_enable_w0 = CONF_ENABLE_W0; + asc->max_peripherals = 3; + asc->segments = aspeed_2600_spi2_segments; + asc->flash_window_base = 0x50000000; + asc->flash_window_size = 0x10000000; + asc->features = ASPEED_SMC_FEATURE_DMA | + ASPEED_SMC_FEATURE_DMA_GRANT; + asc->dma_flash_mask = 0x0FFFFFFC; + asc->dma_dram_mask = 0x3FFFFFFC; + 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; +} + +static const TypeInfo aspeed_2600_spi2_info = { + .name = "aspeed.spi2-ast2600", + .parent = TYPE_ASPEED_SMC, + .class_init = aspeed_2600_spi2_class_init, +}; + static void aspeed_smc_register_types(void) { - int i; - + type_register_static(&aspeed_smc_flash_info); type_register_static(&aspeed_smc_info); - for (i = 0; i < ARRAY_SIZE(controllers); ++i) { - TypeInfo ti = { - .name = controllers[i].name, - .parent = TYPE_ASPEED_SMC, - .class_init = aspeed_smc_class_init, - .class_data = (void *)&controllers[i], - }; - type_register(&ti); - } + type_register_static(&aspeed_2400_smc_info); + type_register_static(&aspeed_2400_fmc_info); + type_register_static(&aspeed_2400_spi1_info); + type_register_static(&aspeed_2500_fmc_info); + type_register_static(&aspeed_2500_spi1_info); + type_register_static(&aspeed_2500_spi2_info); + type_register_static(&aspeed_2600_fmc_info); + type_register_static(&aspeed_2600_spi1_info); + type_register_static(&aspeed_2600_spi2_info); } type_init(aspeed_smc_register_types) diff --git a/hw/watchdog/trace-events b/hw/watchdog/trace-events index c3bafbffa9..e7523e22aa 100644 --- a/hw/watchdog/trace-events +++ b/hw/watchdog/trace-events @@ -5,3 +5,7 @@ cmsdk_apb_watchdog_read(uint64_t offset, uint64_t data, unsigned size) "CMSDK AP cmsdk_apb_watchdog_write(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB watchdog write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u" cmsdk_apb_watchdog_reset(void) "CMSDK APB watchdog: reset" cmsdk_apb_watchdog_lock(uint32_t lock) "CMSDK APB watchdog: lock %" PRIu32 + +# wdt-aspeed.c +aspeed_wdt_read(uint64_t addr, uint32_t size) "@0x%" PRIx64 " size=%d" +aspeed_wdt_write(uint64_t addr, uint32_t size, uint64_t data) "@0x%" PRIx64 " size=%d value=0x%"PRIx64 diff --git a/hw/watchdog/wdt_aspeed.c b/hw/watchdog/wdt_aspeed.c index 69c37af9a6..146ffcd713 100644 --- a/hw/watchdog/wdt_aspeed.c +++ b/hw/watchdog/wdt_aspeed.c @@ -19,6 +19,7 @@ #include "hw/sysbus.h" #include "hw/watchdog/wdt_aspeed.h" #include "migration/vmstate.h" +#include "trace.h" #define WDT_STATUS (0x00 / 4) #define WDT_RELOAD_VALUE (0x04 / 4) @@ -60,6 +61,8 @@ static uint64_t aspeed_wdt_read(void *opaque, hwaddr offset, unsigned size) { AspeedWDTState *s = ASPEED_WDT(opaque); + trace_aspeed_wdt_read(offset, size); + offset >>= 2; switch (offset) { @@ -140,6 +143,8 @@ static void aspeed_wdt_write(void *opaque, hwaddr offset, uint64_t data, AspeedWDTClass *awc = ASPEED_WDT_GET_CLASS(s); bool enable; + trace_aspeed_wdt_write(offset, size, data); + offset >>= 2; switch (offset) { diff --git a/include/hw/adc/aspeed_adc.h b/include/hw/adc/aspeed_adc.h new file mode 100644 index 0000000000..2f166e8be1 --- /dev/null +++ b/include/hw/adc/aspeed_adc.h @@ -0,0 +1,55 @@ +/* + * Aspeed ADC + * + * Copyright 2017-2021 IBM Corp. + * + * Andrew Jeffery + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_ADC_ASPEED_ADC_H +#define HW_ADC_ASPEED_ADC_H + +#include "hw/sysbus.h" + +#define TYPE_ASPEED_ADC "aspeed.adc" +#define TYPE_ASPEED_2400_ADC TYPE_ASPEED_ADC "-ast2400" +#define TYPE_ASPEED_2500_ADC TYPE_ASPEED_ADC "-ast2500" +#define TYPE_ASPEED_2600_ADC TYPE_ASPEED_ADC "-ast2600" +OBJECT_DECLARE_TYPE(AspeedADCState, AspeedADCClass, ASPEED_ADC) + +#define TYPE_ASPEED_ADC_ENGINE "aspeed.adc.engine" +OBJECT_DECLARE_SIMPLE_TYPE(AspeedADCEngineState, ASPEED_ADC_ENGINE) + +#define ASPEED_ADC_NR_CHANNELS 16 +#define ASPEED_ADC_NR_REGS (0xD0 >> 2) + +struct AspeedADCEngineState { + /* */ + SysBusDevice parent; + + MemoryRegion mmio; + qemu_irq irq; + uint32_t engine_id; + uint32_t nr_channels; + uint32_t regs[ASPEED_ADC_NR_REGS]; +}; + +struct AspeedADCState { + /* */ + SysBusDevice parent; + + MemoryRegion mmio; + qemu_irq irq; + + AspeedADCEngineState engines[2]; +}; + +struct AspeedADCClass { + SysBusDeviceClass parent_class; + + uint32_t nr_engines; +}; + +#endif /* HW_ADC_ASPEED_ADC_H */ diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h index 87d76c9259..8139358549 100644 --- a/include/hw/arm/aspeed_soc.h +++ b/include/hw/arm/aspeed_soc.h @@ -15,6 +15,7 @@ #include "hw/cpu/a15mpcore.h" #include "hw/intc/aspeed_vic.h" #include "hw/misc/aspeed_scu.h" +#include "hw/adc/aspeed_adc.h" #include "hw/misc/aspeed_sdmc.h" #include "hw/misc/aspeed_xdma.h" #include "hw/timer/aspeed_timer.h" @@ -53,6 +54,7 @@ struct AspeedSoCState { AspeedSCUState scu; AspeedHACEState hace; AspeedXDMAState xdma; + AspeedADCState adc; AspeedSMCState fmc; AspeedSMCState spi[ASPEED_SPIS_NUM]; EHCISysBusState ehci[ASPEED_EHCIS_NUM]; diff --git a/include/hw/gpio/aspeed_gpio.h b/include/hw/gpio/aspeed_gpio.h index e1636ce7fe..801846befb 100644 --- a/include/hw/gpio/aspeed_gpio.h +++ b/include/hw/gpio/aspeed_gpio.h @@ -17,9 +17,9 @@ OBJECT_DECLARE_TYPE(AspeedGPIOState, AspeedGPIOClass, ASPEED_GPIO) #define ASPEED_GPIO_MAX_NR_SETS 8 +#define ASPEED_GPIOS_PER_SET 32 #define ASPEED_REGS_PER_BANK 14 #define ASPEED_GPIO_MAX_NR_REGS (ASPEED_REGS_PER_BANK * ASPEED_GPIO_MAX_NR_SETS) -#define ASPEED_GPIO_NR_PINS 228 #define ASPEED_GROUPS_PER_SET 4 #define ASPEED_GPIO_NR_DEBOUNCE_REGS 3 #define ASPEED_CHARS_PER_GROUP_LABEL 4 @@ -60,7 +60,6 @@ struct AspeedGPIOClass { const GPIOSetProperties *props; uint32_t nr_gpio_pins; uint32_t nr_gpio_sets; - uint32_t gap; const AspeedGPIOReg *reg_table; }; @@ -72,7 +71,7 @@ struct AspeedGPIOState { MemoryRegion iomem; int pending; qemu_irq irq; - qemu_irq gpios[ASPEED_GPIO_NR_PINS]; + qemu_irq gpios[ASPEED_GPIO_MAX_NR_SETS][ASPEED_GPIOS_PER_SET]; /* Parallel GPIO Registers */ uint32_t debounce_regs[ASPEED_GPIO_NR_DEBOUNCE_REGS]; diff --git a/include/hw/i2c/aspeed_i2c.h b/include/hw/i2c/aspeed_i2c.h index 565f833066..4b9be09274 100644 --- a/include/hw/i2c/aspeed_i2c.h +++ b/include/hw/i2c/aspeed_i2c.h @@ -36,7 +36,11 @@ OBJECT_DECLARE_TYPE(AspeedI2CState, AspeedI2CClass, ASPEED_I2C) struct AspeedI2CState; -typedef struct AspeedI2CBus { +#define TYPE_ASPEED_I2C_BUS "aspeed.i2c.bus" +OBJECT_DECLARE_SIMPLE_TYPE(AspeedI2CBus, ASPEED_I2C_BUS) +struct AspeedI2CBus { + SysBusDevice parent_obj; + struct AspeedI2CState *controller; MemoryRegion mr; @@ -54,7 +58,7 @@ typedef struct AspeedI2CBus { uint32_t pool_ctrl; uint32_t dma_addr; uint32_t dma_len; -} AspeedI2CBus; +}; struct AspeedI2CState { SysBusDevice parent_obj; diff --git a/include/hw/ssi/aspeed_smc.h b/include/hw/ssi/aspeed_smc.h index cdaf165300..75bc793bd2 100644 --- a/include/hw/ssi/aspeed_smc.h +++ b/include/hw/ssi/aspeed_smc.h @@ -29,66 +29,33 @@ #include "hw/sysbus.h" #include "qom/object.h" -typedef struct AspeedSegments { - hwaddr addr; - uint32_t size; -} AspeedSegments; - struct AspeedSMCState; -typedef struct AspeedSMCController { - const char *name; - uint8_t r_conf; - uint8_t r_ce_ctrl; - uint8_t r_ctrl0; - uint8_t r_timings; - uint8_t nregs_timings; - uint8_t conf_enable_w0; - uint8_t max_peripherals; - const AspeedSegments *segments; - hwaddr flash_window_base; - uint32_t flash_window_size; - uint32_t features; - hwaddr dma_flash_mask; - hwaddr dma_dram_mask; - uint32_t nregs; - uint32_t (*segment_to_reg)(const struct AspeedSMCState *s, - const AspeedSegments *seg); - void (*reg_to_segment)(const struct AspeedSMCState *s, uint32_t reg, - AspeedSegments *seg); - void (*dma_ctrl)(struct AspeedSMCState *s, uint32_t value); -} AspeedSMCController; -typedef struct AspeedSMCFlash { +#define TYPE_ASPEED_SMC_FLASH "aspeed.smc.flash" +OBJECT_DECLARE_SIMPLE_TYPE(AspeedSMCFlash, ASPEED_SMC_FLASH) +struct AspeedSMCFlash { + SysBusDevice parent_obj; + struct AspeedSMCState *controller; - - uint8_t id; - uint32_t size; + uint8_t cs; MemoryRegion mmio; - DeviceState *flash; -} AspeedSMCFlash; +}; #define TYPE_ASPEED_SMC "aspeed.smc" OBJECT_DECLARE_TYPE(AspeedSMCState, AspeedSMCClass, ASPEED_SMC) -struct AspeedSMCClass { - SysBusDevice parent_obj; - const AspeedSMCController *ctrl; -}; - #define ASPEED_SMC_R_MAX (0x100 / 4) +#define ASPEED_SMC_CS_MAX 5 struct AspeedSMCState { SysBusDevice parent_obj; - const AspeedSMCController *ctrl; - MemoryRegion mmio; MemoryRegion mmio_flash; MemoryRegion mmio_flash_alias; qemu_irq irq; - int irqline; uint32_t num_cs; qemu_irq *cs_lines; @@ -109,10 +76,41 @@ struct AspeedSMCState { MemoryRegion *dram_mr; AddressSpace dram_as; - AspeedSMCFlash *flashes; + AspeedSMCFlash flashes[ASPEED_SMC_CS_MAX]; uint8_t snoop_index; uint8_t snoop_dummies; }; +typedef struct AspeedSegments { + hwaddr addr; + uint32_t size; +} AspeedSegments; + +struct AspeedSMCClass { + SysBusDeviceClass parent_obj; + + uint8_t r_conf; + uint8_t r_ce_ctrl; + uint8_t r_ctrl0; + uint8_t r_timings; + uint8_t nregs_timings; + uint8_t conf_enable_w0; + uint8_t max_peripherals; + const uint32_t *resets; + const AspeedSegments *segments; + hwaddr flash_window_base; + uint32_t flash_window_size; + uint32_t features; + hwaddr dma_flash_mask; + hwaddr dma_dram_mask; + uint32_t nregs; + uint32_t (*segment_to_reg)(const AspeedSMCState *s, + const AspeedSegments *seg); + void (*reg_to_segment)(const AspeedSMCState *s, uint32_t reg, + AspeedSegments *seg); + void (*dma_ctrl)(AspeedSMCState *s, uint32_t value); + int (*addr_width)(const AspeedSMCState *s); +}; + #endif /* ASPEED_SMC_H */