diff options
Diffstat (limited to 'hw/arm/aspeed_soc_common.c')
-rw-r--r-- | hw/arm/aspeed_soc_common.c | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/hw/arm/aspeed_soc_common.c b/hw/arm/aspeed_soc_common.c index 1c4ac93..bc70e86 100644 --- a/hw/arm/aspeed_soc_common.c +++ b/hw/arm/aspeed_soc_common.c @@ -16,6 +16,10 @@ #include "hw/misc/unimp.h" #include "hw/arm/aspeed_soc.h" #include "hw/char/serial-mm.h" +#include "system/blockdev.h" +#include "system/block-backend.h" +#include "hw/loader.h" +#include "qemu/datadir.h" const char *aspeed_soc_cpu_type(AspeedSoCClass *sc) @@ -124,6 +128,98 @@ void aspeed_mmio_map_unimplemented(AspeedSoCState *s, SysBusDevice *dev, sysbus_mmio_get_region(dev, 0), -1000); } +void aspeed_board_init_flashes(AspeedSMCState *s, const char *flashtype, + unsigned int count, int unit0) +{ + int i; + + if (!flashtype) { + return; + } + + for (i = 0; i < count; ++i) { + DriveInfo *dinfo = drive_get(IF_MTD, 0, unit0 + i); + DeviceState *dev; + + dev = qdev_new(flashtype); + if (dinfo) { + qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(dinfo)); + } + qdev_prop_set_uint8(dev, "cs", i); + qdev_realize_and_unref(dev, BUS(s->spi), &error_fatal); + } +} + +void aspeed_write_boot_rom(BlockBackend *blk, hwaddr addr, size_t rom_size, + Error **errp) +{ + g_autofree void *storage = NULL; + int64_t size; + + /* + * The block backend size should have already been 'validated' by + * the creation of the m25p80 object. + */ + size = blk_getlength(blk); + if (size <= 0) { + error_setg(errp, "failed to get flash size"); + return; + } + + if (rom_size > size) { + rom_size = size; + } + + storage = g_malloc0(rom_size); + if (blk_pread(blk, 0, rom_size, storage, 0) < 0) { + error_setg(errp, "failed to read the initial flash content"); + return; + } + + rom_add_blob_fixed("aspeed.boot_rom", storage, rom_size, addr); +} + +/* + * Create a ROM and copy the flash contents at the expected address + * (0x0). Boots faster than execute-in-place. + */ +void aspeed_install_boot_rom(AspeedSoCState *soc, BlockBackend *blk, + MemoryRegion *boot_rom, uint64_t rom_size) +{ + AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(soc); + + memory_region_init_rom(boot_rom, NULL, "aspeed.boot_rom", rom_size, + &error_abort); + memory_region_add_subregion_overlap(&soc->spi_boot_container, 0, + boot_rom, 1); + aspeed_write_boot_rom(blk, sc->memmap[ASPEED_DEV_SPI_BOOT], rom_size, + &error_abort); +} + +/* + * This function locates the vbootrom image file specified via the command line + * using the -bios option. It loads the specified image into the vbootrom + * memory region and handles errors if the file cannot be found or loaded. + */ +void aspeed_load_vbootrom(AspeedSoCState *soc, const char *bios_name, + Error **errp) +{ + g_autofree char *filename = NULL; + int ret; + + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); + if (!filename) { + error_setg(errp, "Could not find vbootrom image '%s'", bios_name); + return; + } + + ret = load_image_mr(filename, &soc->vbootrom); + if (ret < 0) { + error_setg(errp, "Failed to load vbootrom image '%s'", bios_name); + return; + } +} + static void aspeed_soc_realize(DeviceState *dev, Error **errp) { AspeedSoCState *s = ASPEED_SOC(dev); |