@@ -20,6 +20,7 @@
#include "sysemu/sysemu.h"
#include "hw/intc/arm_gicv3.h"
#include "qapi/qmp/qlist.h"
+#include "qemu/log.h"
static const hwaddr aspeed_soc_ast2700_memmap[] = {
[ASPEED_DEV_SPI_BOOT] = 0x400000000,
@@ -191,6 +192,97 @@ static qemu_irq aspeed_soc_ast2700_get_irq(AspeedSoCState *s, int dev)
return qdev_get_gpio_in(a->intc.gic, sc->irqmap[dev]);
}
+static uint64_t aspeed_ram_capacity_read(void *opaque, hwaddr addr,
+ unsigned int size)
+{
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: read @%" PRIx64 " out of ram size\n",
+ __func__, addr);
+ return 0;
+}
+
+static void aspeed_ram_capacity_write(void *opaque, hwaddr addr, uint64_t data,
+ unsigned int size)
+{
+ AspeedSoCState *s = ASPEED_SOC(opaque);
+ uint32_t test_pattern = 0xdeadbeef;
+ bool invalid_pattern = true;
+ uint32_t *ram_ptr;
+ int sz;
+
+ ram_ptr = memory_region_get_ram_ptr(s->dram_mr);
+
+ /*
+ * Emulate ddr capacity hardware behavior.
+ * If writes the test_pattern to address which is beyond the ram size,
+ * it would write the test_pattern to address 0.
+ */
+ for (sz = 4; sz > 0 ; sz--) {
+ test_pattern = (test_pattern << 4) + sz;
+ if (data == test_pattern) {
+ ram_ptr[0] = test_pattern;
+ invalid_pattern = false;
+ break;
+ }
+ }
+
+ if (invalid_pattern) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: write invalid pattern @%" PRIx64
+ " to addr @%" HWADDR_PRIx "]\n",
+ __func__, data, addr);
+ }
+}
+
+static const MemoryRegionOps aspeed_ram_capacity_ops = {
+ .read = aspeed_ram_capacity_read,
+ .write = aspeed_ram_capacity_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 1,
+ .max_access_size = 8,
+ },
+};
+
+/*
+ * SDMC should be realized first to get correct RAM size and max size
+ * values
+ */
+static bool aspeed_soc_ast2700_dram_init(DeviceState *dev, Error **errp)
+{
+ ram_addr_t ram_size, max_ram_size;
+ Aspeed27x0SoCState *a = ASPEED27X0_SOC(dev);
+ AspeedSoCState *s = ASPEED_SOC(dev);
+ AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
+
+ ram_size = object_property_get_uint(OBJECT(&s->sdmc), "ram-size",
+ &error_abort);
+ max_ram_size = object_property_get_uint(OBJECT(&s->sdmc), "max-ram-size",
+ &error_abort);
+
+ memory_region_init(&s->dram_container, OBJECT(s), "ram-container",
+ ram_size);
+ memory_region_add_subregion(&s->dram_container, 0, s->dram_mr);
+
+ /*
+ * Add a memory region beyond the RAM region to emulate
+ * ddr capacity hardware behavior.
+ */
+ if (ram_size < max_ram_size) {
+ memory_region_init_io(&a->dram_empty, OBJECT(s),
+ &aspeed_ram_capacity_ops, s,
+ "ram-empty", max_ram_size - ram_size);
+
+ memory_region_add_subregion(s->memory,
+ sc->memmap[ASPEED_DEV_SDRAM] + ram_size,
+ &a->dram_empty);
+ }
+
+ memory_region_add_subregion(s->memory,
+ sc->memmap[ASPEED_DEV_SDRAM], &s->dram_container);
+ return true;
+}
+
static void aspeed_soc_ast2700_init(Object *obj)
{
Aspeed27x0SoCState *a = ASPEED27X0_SOC(obj);
@@ -454,7 +546,7 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp)
sc->memmap[ASPEED_DEV_SDMC]);
/* RAM */
- if (!aspeed_soc_dram_init(s, errp)) {
+ if (!aspeed_soc_ast2700_dram_init(dev, errp)) {
return;
}
@@ -127,6 +127,7 @@ struct Aspeed27x0SoCState {
ARMCPU cpu[ASPEED_CPUS_NUM];
AspeedINTCState intc;
+ MemoryRegion dram_empty;
};
#define TYPE_ASPEED27X0_SOC "aspeed27x0-soc"