aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/ppc/Kconfig1
-rw-r--r--hw/ppc/e500.c79
2 files changed, 80 insertions, 0 deletions
diff --git a/hw/ppc/Kconfig b/hw/ppc/Kconfig
index 791fe78..769a1ea 100644
--- a/hw/ppc/Kconfig
+++ b/hw/ppc/Kconfig
@@ -126,6 +126,7 @@ config E500
select ETSEC
select GPIO_MPC8XXX
select OPENPIC
+ select PFLASH_CFI01
select PLATFORM_BUS
select PPCE500_PCI
select SERIAL
diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index 3e950ea..2fe4966 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -23,8 +23,10 @@
#include "e500-ccsr.h"
#include "net/net.h"
#include "qemu/config-file.h"
+#include "hw/block/flash.h"
#include "hw/char/serial.h"
#include "hw/pci/pci.h"
+#include "sysemu/block-backend-io.h"
#include "sysemu/sysemu.h"
#include "sysemu/kvm.h"
#include "sysemu/reset.h"
@@ -267,6 +269,31 @@ static void sysbus_device_create_devtree(SysBusDevice *sbdev, void *opaque)
}
}
+static void create_devtree_flash(SysBusDevice *sbdev,
+ PlatformDevtreeData *data)
+{
+ g_autofree char *name = NULL;
+ uint64_t num_blocks = object_property_get_uint(OBJECT(sbdev),
+ "num-blocks",
+ &error_fatal);
+ uint64_t sector_length = object_property_get_uint(OBJECT(sbdev),
+ "sector-length",
+ &error_fatal);
+ uint64_t bank_width = object_property_get_uint(OBJECT(sbdev),
+ "width",
+ &error_fatal);
+ hwaddr flashbase = 0;
+ hwaddr flashsize = num_blocks * sector_length;
+ void *fdt = data->fdt;
+
+ name = g_strdup_printf("%s/nor@%" PRIx64, data->node, flashbase);
+ qemu_fdt_add_subnode(fdt, name);
+ qemu_fdt_setprop_string(fdt, name, "compatible", "cfi-flash");
+ qemu_fdt_setprop_sized_cells(fdt, name, "reg",
+ 1, flashbase, 1, flashsize);
+ qemu_fdt_setprop_cell(fdt, name, "bank-width", bank_width);
+}
+
static void platform_bus_create_devtree(PPCE500MachineState *pms,
void *fdt, const char *mpic)
{
@@ -276,6 +303,8 @@ static void platform_bus_create_devtree(PPCE500MachineState *pms,
uint64_t addr = pmc->platform_bus_base;
uint64_t size = pmc->platform_bus_size;
int irq_start = pmc->platform_bus_first_irq;
+ SysBusDevice *sbdev;
+ bool ambiguous;
/* Create a /platform node that we can put all devices into */
@@ -302,6 +331,13 @@ static void platform_bus_create_devtree(PPCE500MachineState *pms,
/* Loop through all dynamic sysbus devices and create nodes for them */
foreach_dynamic_sysbus_device(sysbus_device_create_devtree, &data);
+ sbdev = SYS_BUS_DEVICE(object_resolve_path_type("", TYPE_PFLASH_CFI01,
+ &ambiguous));
+ if (sbdev) {
+ assert(!ambiguous);
+ create_devtree_flash(sbdev, &data);
+ }
+
g_free(node);
}
@@ -856,6 +892,7 @@ void ppce500_init(MachineState *machine)
unsigned int pci_irq_nrs[PCI_NUM_PINS] = {1, 2, 3, 4};
IrqLines *irqs;
DeviceState *dev, *mpicdev;
+ DriveInfo *dinfo;
CPUPPCState *firstenv = NULL;
MemoryRegion *ccsr_addr_space;
SysBusDevice *s;
@@ -1024,6 +1061,48 @@ void ppce500_init(MachineState *machine)
pmc->platform_bus_base,
&pms->pbus_dev->mmio);
+ dinfo = drive_get(IF_PFLASH, 0, 0);
+ if (dinfo) {
+ BlockBackend *blk = blk_by_legacy_dinfo(dinfo);
+ BlockDriverState *bs = blk_bs(blk);
+ uint64_t mmio_size = memory_region_size(&pms->pbus_dev->mmio);
+ uint64_t size = bdrv_getlength(bs);
+ uint32_t sector_len = 64 * KiB;
+
+ if (!is_power_of_2(size)) {
+ error_report("Size of pflash file must be a power of two.");
+ exit(1);
+ }
+
+ if (size > mmio_size) {
+ error_report("Size of pflash file must not be bigger than %" PRIu64
+ " bytes.", mmio_size);
+ exit(1);
+ }
+
+ if (!QEMU_IS_ALIGNED(size, sector_len)) {
+ error_report("Size of pflash file must be a multiple of %" PRIu32
+ ".", sector_len);
+ exit(1);
+ }
+
+ dev = qdev_new(TYPE_PFLASH_CFI01);
+ qdev_prop_set_drive(dev, "drive", blk);
+ qdev_prop_set_uint32(dev, "num-blocks", size / sector_len);
+ qdev_prop_set_uint64(dev, "sector-length", sector_len);
+ qdev_prop_set_uint8(dev, "width", 2);
+ qdev_prop_set_bit(dev, "big-endian", true);
+ qdev_prop_set_uint16(dev, "id0", 0x89);
+ qdev_prop_set_uint16(dev, "id1", 0x18);
+ qdev_prop_set_uint16(dev, "id2", 0x0000);
+ qdev_prop_set_uint16(dev, "id3", 0x0);
+ qdev_prop_set_string(dev, "name", "e500.flash");
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+
+ memory_region_add_subregion(&pms->pbus_dev->mmio, 0,
+ pflash_cfi01_get_memory(PFLASH_CFI01(dev)));
+ }
+
/*
* Smart firmware defaults ahead!
*