Add cfi01 pflash device for LoongArch virt machine Signed-off-by: Xiaojuan Yang <yangxiaoj...@loongson.cn> --- hw/loongarch/Kconfig | 1 + hw/loongarch/acpi-build.c | 39 +++++++++++ hw/loongarch/virt.c | 130 +++++++++++++++++++++++++++++++++--- include/hw/loongarch/virt.h | 7 ++ 4 files changed, 168 insertions(+), 9 deletions(-)
diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig index 17d15b6c90..eb112af990 100644 --- a/hw/loongarch/Kconfig +++ b/hw/loongarch/Kconfig @@ -20,3 +20,4 @@ config LOONGARCH_VIRT select ACPI_HW_REDUCED select FW_CFG_DMA select DIMM + select PFLASH_CFI01 diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c index 7d5f5a757d..7b08bd9670 100644 --- a/hw/loongarch/acpi-build.c +++ b/hw/loongarch/acpi-build.c @@ -279,6 +279,44 @@ static void build_pci_device_aml(Aml *scope, LoongArchMachineState *lams) acpi_dsdt_add_gpex(scope, &cfg); } +static void build_flash_aml(Aml *scope, LoongArchMachineState *lams) +{ + Aml *dev, *crs; + MemoryRegion *flash_mem; + + hwaddr flash0_base; + hwaddr flash0_size; + + hwaddr flash1_base; + hwaddr flash1_size; + + flash_mem = pflash_cfi01_get_memory(lams->flash[0]); + flash0_base = flash_mem->addr; + flash0_size = flash_mem->size; + + flash_mem = pflash_cfi01_get_memory(lams->flash[1]); + flash1_base = flash_mem->addr; + flash1_size = flash_mem->size; + + dev = aml_device("FLS0"); + aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0015"))); + aml_append(dev, aml_name_decl("_UID", aml_int(0))); + + crs = aml_resource_template(); + aml_append(crs, aml_memory32_fixed(flash0_base, flash0_size, AML_READ_WRITE)); + aml_append(dev, aml_name_decl("_CRS", crs)); + aml_append(scope, dev); + + dev = aml_device("FLS1"); + aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0015"))); + aml_append(dev, aml_name_decl("_UID", aml_int(1))); + + crs = aml_resource_template(); + aml_append(crs, aml_memory32_fixed(flash1_base, flash1_size, AML_READ_WRITE)); + aml_append(dev, aml_name_decl("_CRS", crs)); + aml_append(scope, dev); +} + #ifdef CONFIG_TPM static void acpi_dsdt_add_tpm(Aml *scope, LoongArchMachineState *vms) { @@ -328,6 +366,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, MachineState *machine) build_uart_device_aml(dsdt); build_pci_device_aml(dsdt, lams); build_la_ged_aml(dsdt, machine); + build_flash_aml(dsdt, lams); #ifdef CONFIG_TPM acpi_dsdt_add_tpm(dsdt, lams); #endif diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c index b59c07972a..c488637fad 100644 --- a/hw/loongarch/virt.c +++ b/hw/loongarch/virt.c @@ -42,6 +42,100 @@ #include "hw/display/ramfb.h" #include "hw/mem/pc-dimm.h" #include "sysemu/tpm.h" +#include "sysemu/block-backend.h" +#include "hw/block/flash.h" + +static PFlashCFI01 *virt_flash_create1(LoongArchMachineState *lams, + const char *name, + const char *alias_prop_name) +{ + DeviceState *dev = qdev_new(TYPE_PFLASH_CFI01); + + qdev_prop_set_uint64(dev, "sector-length", VIRT_FLASH_SECTOR_SIZE); + qdev_prop_set_uint8(dev, "width", 4); + qdev_prop_set_uint8(dev, "device-width", 2); + qdev_prop_set_bit(dev, "big-endian", false); + qdev_prop_set_uint16(dev, "id0", 0x89); + qdev_prop_set_uint16(dev, "id1", 0x18); + qdev_prop_set_uint16(dev, "id2", 0x00); + qdev_prop_set_uint16(dev, "id3", 0x00); + qdev_prop_set_string(dev, "name", name); + object_property_add_child(OBJECT(lams), name, OBJECT(dev)); + object_property_add_alias(OBJECT(lams), alias_prop_name, + OBJECT(dev), "drive"); + return PFLASH_CFI01(dev); +} + +static void virt_flash_create(LoongArchMachineState *lams) +{ + lams->flash[0] = virt_flash_create1(lams, "virt.flash0", "pflash0"); + lams->flash[1] = virt_flash_create1(lams, "virt.flash1", "pflash1"); +} + +static void virt_flash_map1(PFlashCFI01 *flash, + hwaddr base, hwaddr size, + MemoryRegion *sysmem, + int flash_id) +{ + DeviceState *dev = DEVICE(flash); + BlockBackend *blk; + hwaddr real_size = size; + + blk = pflash_cfi01_get_blk(flash); + if (blk) { + real_size = blk_getlength(blk); + assert(real_size && real_size <= size); + } + + assert(QEMU_IS_ALIGNED(real_size, VIRT_FLASH_SECTOR_SIZE)); + assert(real_size / VIRT_FLASH_SECTOR_SIZE <= UINT32_MAX); + + qdev_prop_set_uint32(dev, "num-blocks", real_size / VIRT_FLASH_SECTOR_SIZE); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + memory_region_add_subregion(sysmem, base, + sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), + 0)); +} + +static void virt_flash_map(LoongArchMachineState *lams, + MemoryRegion *sysmem) +{ + PFlashCFI01 *flash0 = lams->flash[0]; + PFlashCFI01 *flash1 = lams->flash[1]; + + virt_flash_map1(flash0, VIRT_FLASH0_BASE, VIRT_FLASH0_SIZE, sysmem, 0); + virt_flash_map1(flash1, VIRT_FLASH1_BASE, VIRT_FLASH1_SIZE, sysmem, 1); +} + +static void fdt_add_flash_node(LoongArchMachineState *lams) +{ + MachineState *ms = MACHINE(lams); + char *nodename; + MemoryRegion *flash_mem; + + hwaddr flash0_base; + hwaddr flash0_size; + + hwaddr flash1_base; + hwaddr flash1_size; + + flash_mem = pflash_cfi01_get_memory(lams->flash[0]); + flash0_base = flash_mem->addr; + flash0_size = flash_mem->size; + + flash_mem = pflash_cfi01_get_memory(lams->flash[1]); + flash1_base = flash_mem->addr; + flash1_size = flash_mem->size; + + nodename = g_strdup_printf("/flash@%" PRIx64, flash0_base); + qemu_fdt_add_subnode(ms->fdt, nodename); + qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "cfi-flash"); + qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", + 2, flash0_base, 2, flash0_size, + 2, flash1_base, 2, flash1_size); + qemu_fdt_setprop_cell(ms->fdt, nodename, "bank-width", 4); + g_free(nodename); +} static void fdt_add_rtc_node(LoongArchMachineState *lams) { @@ -593,28 +687,44 @@ static void loongarch_firmware_init(LoongArchMachineState *lams) { char *filename = MACHINE(lams)->firmware; char *bios_name = NULL; - int bios_size; + int bios_size, i; + BlockBackend *pflash_blk0; + MemoryRegion *mr; lams->bios_loaded = false; + /* Map legacy -drive if=pflash to machine properties */ + for (i = 0; i < ARRAY_SIZE(lams->flash); i++) { + pflash_cfi01_legacy_drive(lams->flash[i], + drive_get(IF_PFLASH, 0, i)); + } + + virt_flash_map(lams, get_system_memory()); + + pflash_blk0 = pflash_cfi01_get_blk(lams->flash[0]); + + if (pflash_blk0) { + if (filename) { + error_report("cannot use both '-bios' and '-drive if=pflash'" + "options at once"); + exit(1); + } + lams->bios_loaded = true; + return; + } + if (filename) { bios_name = qemu_find_file(QEMU_FILE_TYPE_BIOS, filename); if (!bios_name) { error_report("Could not find ROM image '%s'", filename); exit(1); } - - bios_size = load_image_targphys(bios_name, VIRT_BIOS_BASE, VIRT_BIOS_SIZE); + mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(lams->flash[0]), 0); + bios_size = load_image_mr(bios_name, mr); if (bios_size < 0) { error_report("Could not load ROM image '%s'", bios_name); exit(1); } - g_free(bios_name); - - memory_region_init_ram(&lams->bios, NULL, "loongarch.bios", - VIRT_BIOS_SIZE, &error_fatal); - memory_region_set_readonly(&lams->bios, true); - memory_region_add_subregion(get_system_memory(), VIRT_BIOS_BASE, &lams->bios); lams->bios_loaded = true; } @@ -779,6 +889,7 @@ static void loongarch_init(MachineState *machine) loongarch_direct_kernel_boot(lams); } } + fdt_add_flash_node(lams); /* register reset function */ for (i = 0; i < machine->smp.cpus; i++) { lacpu = LOONGARCH_CPU(qemu_get_cpu(i)); @@ -838,6 +949,7 @@ static void loongarch_machine_initfn(Object *obj) lams->acpi = ON_OFF_AUTO_AUTO; lams->oem_id = g_strndup(ACPI_BUILD_APPNAME6, 6); lams->oem_table_id = g_strndup(ACPI_BUILD_APPNAME8, 8); + virt_flash_create(lams); } static bool memhp_type_supported(DeviceState *dev) diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h index 45c383f5a7..4ec4a7b4fe 100644 --- a/include/hw/loongarch/virt.h +++ b/include/hw/loongarch/virt.h @@ -12,6 +12,7 @@ #include "hw/boards.h" #include "qemu/queue.h" #include "hw/intc/loongarch_ipi.h" +#include "hw/block/flash.h" #define LOONGARCH_MAX_VCPUS 4 @@ -20,6 +21,11 @@ #define VIRT_FWCFG_BASE 0x1e020000UL #define VIRT_BIOS_BASE 0x1c000000UL #define VIRT_BIOS_SIZE (4 * MiB) +#define VIRT_FLASH_SECTOR_SIZE (128 * KiB) +#define VIRT_FLASH0_BASE VIRT_BIOS_BASE +#define VIRT_FLASH0_SIZE (4 * MiB) +#define VIRT_FLASH1_BASE (VIRT_FLASH0_BASE + VIRT_FLASH0_SIZE) +#define VIRT_FLASH1_SIZE (4 * MiB) #define VIRT_LOWMEM_BASE 0 #define VIRT_LOWMEM_SIZE 0x10000000 @@ -48,6 +54,7 @@ struct LoongArchMachineState { int fdt_size; DeviceState *platform_bus_dev; PCIBus *pci_bus; + PFlashCFI01 *flash[2]; }; #define TYPE_LOONGARCH_MACHINE MACHINE_TYPE_NAME("virt") -- 2.31.1