summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Henderson2021-10-12 13:41:59 +0200
committerRichard Henderson2021-10-12 13:41:59 +0200
commit81d8537cb297d57b0897797f1329e4d755a0eaf4 (patch)
tree360aa93c0291dc6557a7dbe6a45de2779e584ddd
parentMerge remote-tracking branch 'remotes/stefanha/tags/block-pull-request' into ... (diff)
parentaspeed/smc: Dump address offset in trace events (diff)
downloadqemu-81d8537cb297d57b0897797f1329e4d755a0eaf4.tar.gz
qemu-81d8537cb297d57b0897797f1329e4d755a0eaf4.tar.xz
qemu-81d8537cb297d57b0897797f1329e4d755a0eaf4.zip
Merge remote-tracking branch 'remotes/clg/tags/pull-aspeed-20211012' into staging
Aspeed patches : * I2C QOMify (Cedric) * SMC model cleanup and QOMify (Cedric) * ADC model (Peter and Andrew) * GPIO fixes (Peter) # gpg: Signature made Tue 12 Oct 2021 12:36:22 AM PDT # gpg: using RSA key A0F66548F04895EBFE6B0B6051A343C7CFFBECA1 # gpg: Good signature from "Cédric Le Goater <clg@kaod.org>" [marginal] # gpg: WARNING: This key is not certified with sufficiently trusted signatures! # gpg: It is not certain that the signature belongs to the owner. # Primary key fingerprint: A0F6 6548 F048 95EB FE6B 0B60 51A3 43C7 CFFB ECA1 * remotes/clg/tags/pull-aspeed-20211012: aspeed/smc: Dump address offset in trace events aspeed/wdt: Add trace events hw/arm: Integrate ADC model into Aspeed SoC hw/adc: Add basic Aspeed ADC model hw: aspeed_gpio: Fix GPIO array indexing hw: aspeed_gpio: Fix pin I/O type declarations aspeed/i2c: QOMify AspeedI2CBus aspeed/smc: Remove unused attribute 'irqline' aspeed/smc: Introduce a new addr_width() class handler aspeed/smc: Add default reset values aspeed/smc: QOMify AspeedSMCFlash aspeed/smc: Rename AspeedSMCFlash 'id' to 'cs' aspeed/smc: Remove the 'size' attribute from AspeedSMCFlash aspeed/smc: Remove the 'flash' attribute from AspeedSMCFlash aspeed/smc: Drop AspeedSMCController structure aspeed/smc: Stop using the model name for the memory regions aspeed/smc: Introduce aspeed_smc_error() helper aspeed/smc: Add watchdog Control/Status Registers Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
-rw-r--r--hw/adc/aspeed_adc.c427
-rw-r--r--hw/adc/meson.build1
-rw-r--r--hw/adc/trace-events3
-rw-r--r--hw/arm/aspeed.c18
-rw-r--r--hw/arm/aspeed_ast2600.c22
-rw-r--r--hw/arm/aspeed_soc.c15
-rw-r--r--hw/gpio/aspeed_gpio.c88
-rw-r--r--hw/i2c/aspeed_i2c.c101
-rw-r--r--hw/ssi/aspeed_smc.c1134
-rw-r--r--hw/watchdog/trace-events4
-rw-r--r--hw/watchdog/wdt_aspeed.c5
-rw-r--r--include/hw/adc/aspeed_adc.h55
-rw-r--r--include/hw/arm/aspeed_soc.h2
-rw-r--r--include/hw/gpio/aspeed_gpio.h5
-rw-r--r--include/hw/i2c/aspeed_i2c.h8
-rw-r--r--include/hw/ssi/aspeed_smc.h82
16 files changed, 1352 insertions, 618 deletions
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 <andrew@aj.id.au>
+ *
+ * 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)
-{
- return !!(s->ctrl->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_dma(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_DMA);
}
-static void aspeed_smc_reg_to_segment(const AspeedSMCState *s,
- uint32_t reg, AspeedSegments *seg)
+static inline bool aspeed_smc_has_wdt_control(const AspeedSMCClass *asc)
{
- 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;
+ return !!(asc->features & ASPEED_SMC_FEATURE_WDT_CONTROL);
}
-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_register_types(void)
+static void aspeed_smc_flash_realize(DeviceState *dev, Error **errp)
{
- int i;
+ AspeedSMCFlash *s = ASPEED_SMC_FLASH(dev);
+ AspeedSMCClass *asc;
+ g_autofree char *name = g_strdup_printf(TYPE_ASPEED_SMC_FLASH ".%d", s->cs);
- 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);
+ 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)
+{
+ type_register_static(&aspeed_smc_flash_info);
+ type_register_static(&aspeed_smc_info);
+ 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 <andrew@aj.id.au>
+ *
+ * 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 {
+ /* <private> */
+ SysBusDevice parent;
+
+ MemoryRegion mmio;
+ qemu_irq irq;
+ uint32_t engine_id;
+ uint32_t nr_channels;
+ uint32_t regs[ASPEED_ADC_NR_REGS];
+};
+
+struct AspeedADCState {
+ /* <private> */
+ 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 {
- struct AspeedSMCState *controller;
+#define TYPE_ASPEED_SMC_FLASH "aspeed.smc.flash"
+OBJECT_DECLARE_SIMPLE_TYPE(AspeedSMCFlash, ASPEED_SMC_FLASH)
+struct AspeedSMCFlash {
+ SysBusDevice parent_obj;
- uint8_t id;
- uint32_t size;
+ struct AspeedSMCState *controller;
+ 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 */