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 | 18 +++++++++ hw/loongarch/virt.c | 80 ++++++++++++++++++++++++++++++++++++- include/hw/loongarch/virt.h | 5 +++ 4 files changed, 103 insertions(+), 1 deletion(-)
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..bc5f5fe9dc 100644 --- a/hw/loongarch/acpi-build.c +++ b/hw/loongarch/acpi-build.c @@ -279,6 +279,23 @@ 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; + + hwaddr flash0_base = VIRT_FLASH0_BASE; + hwaddr flash0_size = VIRT_FLASH0_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); +} + #ifdef CONFIG_TPM static void acpi_dsdt_add_tpm(Aml *scope, LoongArchMachineState *vms) { @@ -328,6 +345,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 958be74fa1..ded77a2f3e 100644 --- a/hw/loongarch/virt.c +++ b/hw/loongarch/virt.c @@ -42,6 +42,74 @@ #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"); +} + +static void virt_flash_map1(PFlashCFI01 *flash, + hwaddr base, hwaddr size, + MemoryRegion *sysmem) +{ + DeviceState *dev = DEVICE(flash); + + assert(QEMU_IS_ALIGNED(size, VIRT_FLASH_SECTOR_SIZE)); + assert(size / VIRT_FLASH_SECTOR_SIZE <= UINT32_MAX); + + qdev_prop_set_uint32(dev, "num-blocks", 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]; + + virt_flash_map1(flash0, VIRT_FLASH0_BASE, VIRT_FLASH0_SIZE, sysmem); +} + +static void fdt_add_flash_node(LoongArchMachineState *lams) +{ + MachineState *ms = MACHINE(lams); + char *nodename; + + hwaddr flash0_base = VIRT_FLASH0_BASE; + hwaddr flash0_size = VIRT_FLASH0_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); + qemu_fdt_setprop_cell(ms->fdt, nodename, "bank-width", 4); + g_free(nodename); +} static void fdt_add_rtc_node(LoongArchMachineState *lams) { @@ -593,9 +661,17 @@ static void loongarch_firmware_init(LoongArchMachineState *lams) { char *filename = MACHINE(lams)->firmware; char *bios_name = NULL; - int bios_size; + int bios_size, i; 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()); + if (filename) { bios_name = qemu_find_file(QEMU_FILE_TYPE_BIOS, filename); if (!bios_name) { @@ -779,6 +855,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 +915,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..94afc92850 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,9 @@ #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 + VIRT_BIOS_SIZE) +#define VIRT_FLASH0_SIZE (4 * MiB) #define VIRT_LOWMEM_BASE 0 #define VIRT_LOWMEM_SIZE 0x10000000 @@ -48,6 +52,7 @@ struct LoongArchMachineState { int fdt_size; DeviceState *platform_bus_dev; PCIBus *pci_bus; + PFlashCFI01 *flash[1]; }; #define TYPE_LOONGARCH_MACHINE MACHINE_TYPE_NAME("virt") -- 2.31.1