diff --git a/MAINTAINERS b/MAINTAINERS index f169fec6fc..e3d5b7e09c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -267,8 +267,8 @@ F: hw/openrisc/ F: tests/tcg/openrisc/ PowerPC TCG CPUs -M: Cédric Le Goater M: Daniel Henrique Barboza +R: Cédric Le Goater R: David Gibson R: Greg Kurz L: qemu-ppc@nongnu.org @@ -392,8 +392,8 @@ F: target/mips/kvm* F: target/mips/sysemu/ PPC KVM CPUs -M: Cédric Le Goater M: Daniel Henrique Barboza +R: Cédric Le Goater R: David Gibson R: Greg Kurz S: Maintained @@ -1365,8 +1365,8 @@ F: include/hw/rtc/m48t59.h F: tests/avocado/ppc_prep_40p.py sPAPR (pseries) -M: Cédric Le Goater M: Daniel Henrique Barboza +R: Cédric Le Goater R: David Gibson R: Greg Kurz L: qemu-ppc@nongnu.org @@ -1387,7 +1387,7 @@ F: tests/avocado/ppc_pseries.py PowerNV (Non-Virtualized) M: Cédric Le Goater L: qemu-ppc@nongnu.org -S: Maintained +S: Odd Fixes F: docs/system/ppc/powernv.rst F: hw/ppc/pnv* F: hw/intc/pnv* @@ -2333,7 +2333,7 @@ T: git https://github.com/philmd/qemu.git fw_cfg-next XIVE M: Cédric Le Goater L: qemu-ppc@nongnu.org -S: Supported +S: Odd Fixes F: hw/*/*xive* F: include/hw/*/*xive* F: docs/*/*xive* diff --git a/configs/devices/ppc-softmmu/default.mak b/configs/devices/ppc-softmmu/default.mak index 658a454426..a887f5438b 100644 --- a/configs/devices/ppc-softmmu/default.mak +++ b/configs/devices/ppc-softmmu/default.mak @@ -1,7 +1,8 @@ # Default configuration for ppc-softmmu # For embedded PPCs: -CONFIG_E500=y +CONFIG_E500PLAT=y +CONFIG_MPC8544DS=y CONFIG_PPC405=y CONFIG_PPC440=y CONFIG_VIRTEX=y diff --git a/docs/system/ppc/ppce500.rst b/docs/system/ppc/ppce500.rst index 9beef39171..ba6bcb7314 100644 --- a/docs/system/ppc/ppce500.rst +++ b/docs/system/ppc/ppce500.rst @@ -146,6 +146,9 @@ You can specify a real world SoC device that QEMU has built-in support but all these SoCs are e500v2 based MPC85xx series, hence you cannot test anything built for P4080 (e500mc), P5020 (e5500) and T2080 (e6500). +Networking +---------- + By default a VirtIO standard PCI networking device is connected as an ethernet interface at PCI address 0.1.0, but we can switch that to an e1000 NIC by: diff --git a/hmp-commands.hx b/hmp-commands.hx index 8ab8000acd..12b6d4e2dc 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -1800,3 +1800,18 @@ ERST .sub_table = hmp_info_cmds, .flags = "p", }, + +#if defined(CONFIG_FDT) + { + .name = "dumpdtb", + .args_type = "filename:F", + .params = "filename", + .help = "dump the FDT in dtb format to 'filename'", + .cmd = hmp_dumpdtb, + }, + +SRST +``dumpdtb`` *filename* + Dump the FDT in dtb format to *filename*. +ERST +#endif diff --git a/hw/gpio/Kconfig b/hw/gpio/Kconfig index f0e7405f6e..d2cf3accc8 100644 --- a/hw/gpio/Kconfig +++ b/hw/gpio/Kconfig @@ -8,6 +8,9 @@ config PL061 config GPIO_KEY bool +config GPIO_MPC8XXX + bool + config GPIO_PWR bool diff --git a/hw/gpio/meson.build b/hw/gpio/meson.build index 7bd6a57264..b726e6d27a 100644 --- a/hw/gpio/meson.build +++ b/hw/gpio/meson.build @@ -1,5 +1,5 @@ -softmmu_ss.add(when: 'CONFIG_E500', if_true: files('mpc8xxx.c')) softmmu_ss.add(when: 'CONFIG_GPIO_KEY', if_true: files('gpio_key.c')) +softmmu_ss.add(when: 'CONFIG_GPIO_MPC8XXX', if_true: files('mpc8xxx.c')) softmmu_ss.add(when: 'CONFIG_GPIO_PWR', if_true: files('gpio_pwr.c')) softmmu_ss.add(when: 'CONFIG_MAX7310', if_true: files('max7310.c')) softmmu_ss.add(when: 'CONFIG_PL061', if_true: files('pl061.c')) diff --git a/hw/nios2/boot.c b/hw/nios2/boot.c index 21cbffff47..b30a7b1efb 100644 --- a/hw/nios2/boot.c +++ b/hw/nios2/boot.c @@ -43,6 +43,8 @@ #include "boot.h" +#include + #define NIOS2_MAGIC 0x534f494e static struct nios2_boot_info { @@ -81,6 +83,7 @@ static uint64_t translate_kernel_address(void *opaque, uint64_t addr) static int nios2_load_dtb(struct nios2_boot_info bi, const uint32_t ramsize, const char *kernel_cmdline, const char *dtb_filename) { + MachineState *machine = MACHINE(qdev_get_machine()); int fdt_size; void *fdt = NULL; int r; @@ -113,7 +116,10 @@ static int nios2_load_dtb(struct nios2_boot_info bi, const uint32_t ramsize, } cpu_physical_memory_write(bi.fdt, fdt, fdt_size); - g_free(fdt); + + /* Set machine->fdt for 'dumpdtb' QMP/HMP command */ + machine->fdt = fdt; + return fdt_size; } diff --git a/hw/nios2/meson.build b/hw/nios2/meson.build index 6c58e8082b..22277bd6c5 100644 --- a/hw/nios2/meson.build +++ b/hw/nios2/meson.build @@ -1,5 +1,5 @@ nios2_ss = ss.source_set() -nios2_ss.add(files('boot.c')) +nios2_ss.add(files('boot.c'), fdt) nios2_ss.add(when: 'CONFIG_NIOS2_10M50', if_true: files('10m50_devboard.c')) nios2_ss.add(when: 'CONFIG_NIOS2_GENERIC_NOMMU', if_true: files('generic_nommu.c')) diff --git a/hw/ppc/Kconfig b/hw/ppc/Kconfig index 3a4418a69e..791fe78a50 100644 --- a/hw/ppc/Kconfig +++ b/hw/ppc/Kconfig @@ -124,6 +124,7 @@ config E500 imply AT24C imply VIRTIO_PCI select ETSEC + select GPIO_MPC8XXX select OPENPIC select PLATFORM_BUS select PPCE500_PCI @@ -132,6 +133,14 @@ config E500 select FDT_PPC select DS1338 +config E500PLAT + bool + select E500 + +config MPC8544DS + bool + select E500 + config VIRTEX bool select PPC4XX diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index 32495d0123..3e950ea3ba 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -1007,25 +1007,23 @@ void ppce500_init(MachineState *machine) } /* Platform Bus Device */ - if (pmc->has_platform_bus) { - dev = qdev_new(TYPE_PLATFORM_BUS_DEVICE); - dev->id = g_strdup(TYPE_PLATFORM_BUS_DEVICE); - qdev_prop_set_uint32(dev, "num_irqs", pmc->platform_bus_num_irqs); - qdev_prop_set_uint32(dev, "mmio_size", pmc->platform_bus_size); - sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - pms->pbus_dev = PLATFORM_BUS_DEVICE(dev); + dev = qdev_new(TYPE_PLATFORM_BUS_DEVICE); + dev->id = g_strdup(TYPE_PLATFORM_BUS_DEVICE); + qdev_prop_set_uint32(dev, "num_irqs", pmc->platform_bus_num_irqs); + qdev_prop_set_uint32(dev, "mmio_size", pmc->platform_bus_size); + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); + pms->pbus_dev = PLATFORM_BUS_DEVICE(dev); - s = SYS_BUS_DEVICE(pms->pbus_dev); - for (i = 0; i < pmc->platform_bus_num_irqs; i++) { - int irqn = pmc->platform_bus_first_irq + i; - sysbus_connect_irq(s, i, qdev_get_gpio_in(mpicdev, irqn)); - } - - memory_region_add_subregion(address_space_mem, - pmc->platform_bus_base, - sysbus_mmio_get_region(s, 0)); + s = SYS_BUS_DEVICE(pms->pbus_dev); + for (i = 0; i < pmc->platform_bus_num_irqs; i++) { + int irqn = pmc->platform_bus_first_irq + i; + sysbus_connect_irq(s, i, qdev_get_gpio_in(mpicdev, irqn)); } + memory_region_add_subregion(address_space_mem, + pmc->platform_bus_base, + &pms->pbus_dev->mmio); + /* * Smart firmware defaults ahead! * diff --git a/hw/ppc/e500.h b/hw/ppc/e500.h index 1e5853b032..68f754ce50 100644 --- a/hw/ppc/e500.h +++ b/hw/ppc/e500.h @@ -27,7 +27,6 @@ struct PPCE500MachineClass { int mpic_version; bool has_mpc8xxx_gpio; - bool has_platform_bus; hwaddr platform_bus_base; hwaddr platform_bus_size; int platform_bus_first_irq; diff --git a/hw/ppc/e500plat.c b/hw/ppc/e500plat.c index fc911bbb7b..5bb1c603da 100644 --- a/hw/ppc/e500plat.c +++ b/hw/ppc/e500plat.c @@ -86,7 +86,6 @@ static void e500plat_machine_class_init(ObjectClass *oc, void *data) pmc->fixup_devtree = e500plat_fixup_devtree; pmc->mpic_version = OPENPIC_MODEL_FSL_MPIC_42; pmc->has_mpc8xxx_gpio = true; - pmc->has_platform_bus = true; pmc->platform_bus_base = 0xf00000000ULL; pmc->platform_bus_size = 128 * MiB; pmc->platform_bus_first_irq = 5; diff --git a/hw/ppc/meson.build b/hw/ppc/meson.build index 62801923f3..32babc9b48 100644 --- a/hw/ppc/meson.build +++ b/hw/ppc/meson.build @@ -71,12 +71,10 @@ ppc_ss.add(when: 'CONFIG_MAC_OLDWORLD', if_true: files('mac_oldworld.c')) # NewWorld PowerMac ppc_ss.add(when: 'CONFIG_MAC_NEWWORLD', if_true: files('mac_newworld.c')) # e500 +ppc_ss.add(when: 'CONFIG_E500PLAT', if_true: files('e500plat.c')) +ppc_ss.add(when: 'CONFIG_MPC8544DS', if_true: files('mpc8544ds.c')) ppc_ss.add(when: 'CONFIG_E500', if_true: files( 'e500.c', - 'mpc8544ds.c', - 'e500plat.c' -)) -ppc_ss.add(when: 'CONFIG_E500', if_true: files( 'mpc8544_guts.c', 'ppce500_spin.c' )) diff --git a/hw/ppc/mpc8544ds.c b/hw/ppc/mpc8544ds.c index 81177505f0..7dd5219736 100644 --- a/hw/ppc/mpc8544ds.c +++ b/hw/ppc/mpc8544ds.c @@ -14,6 +14,7 @@ #include "sysemu/device_tree.h" #include "hw/ppc/openpic.h" #include "qemu/error-report.h" +#include "qemu/units.h" #include "cpu.h" static void mpc8544ds_fixup_devtree(void *fdt) @@ -36,7 +37,7 @@ static void mpc8544ds_init(MachineState *machine) ppce500_init(machine); } -static void e500plat_machine_class_init(ObjectClass *oc, void *data) +static void mpc8544ds_machine_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); PPCE500MachineClass *pmc = PPCE500_MACHINE_CLASS(oc); @@ -45,6 +46,10 @@ static void e500plat_machine_class_init(ObjectClass *oc, void *data) pmc->pci_nr_slots = 2; pmc->fixup_devtree = mpc8544ds_fixup_devtree; pmc->mpic_version = OPENPIC_MODEL_FSL_MPIC_20; + pmc->platform_bus_base = 0xFF800000ULL; + pmc->platform_bus_size = 8 * MiB; + pmc->platform_bus_first_irq = 5; + pmc->platform_bus_num_irqs = 10; pmc->ccsrbar_base = 0xE0000000ULL; pmc->pci_mmio_base = 0xC0000000ULL; pmc->pci_mmio_bus_base = 0xC0000000ULL; @@ -63,7 +68,7 @@ static void e500plat_machine_class_init(ObjectClass *oc, void *data) static const TypeInfo mpc8544ds_info = { .name = TYPE_MPC8544DS_MACHINE, .parent = TYPE_PPCE500_MACHINE, - .class_init = e500plat_machine_class_init, + .class_init = mpc8544ds_machine_class_init, }; static void mpc8544ds_register_types(void) diff --git a/hw/ppc/pegasos2.c b/hw/ppc/pegasos2.c index 61f4263953..ecf682b148 100644 --- a/hw/ppc/pegasos2.c +++ b/hw/ppc/pegasos2.c @@ -331,6 +331,10 @@ static void pegasos2_machine_reset(MachineState *machine) vof_build_dt(fdt, pm->vof); vof_client_open_store(fdt, pm->vof, "/chosen", "stdout", "/failsafe"); + + /* Set machine->fdt for 'dumpdtb' QMP/HMP command */ + machine->fdt = fdt; + pm->cpu->vhyp = PPC_VIRTUAL_HYPERVISOR(machine); } diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 78e00afb9b..40bb573d1a 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -678,7 +678,13 @@ static void pnv_reset(MachineState *machine) qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt)); cpu_physical_memory_write(PNV_FDT_ADDR, fdt, fdt_totalsize(fdt)); - g_free(fdt); + /* + * Set machine->fdt for 'dumpdtb' QMP/HMP command. Free + * the existing machine->fdt to avoid leaking it during + * a reset. + */ + g_free(machine->fdt); + machine->fdt = fdt; } static ISABus *pnv_chip_power8_isa_create(PnvChip *chip, Error **errp) diff --git a/hw/ppc/ppc405.h b/hw/ppc/ppc405.h index 1e558c7831..9a4312691e 100644 --- a/hw/ppc/ppc405.h +++ b/hw/ppc/ppc405.h @@ -167,13 +167,6 @@ struct Ppc405SoCState { DeviceState parent_obj; /* Public */ - MemoryRegion ram_banks[2]; - hwaddr ram_bases[2], ram_sizes[2]; - bool do_dram_init; - - MemoryRegion *dram_mr; - hwaddr ram_size; - PowerPCCPU cpu; PPCUIC uic; Ppc405CpcState cpc; @@ -187,6 +180,7 @@ struct Ppc405SoCState { Ppc405PobState pob; Ppc4xxPlbState plb; Ppc4xxMalState mal; + Ppc4xxSdramDdrState sdram; }; #endif /* PPC405_H */ diff --git a/hw/ppc/ppc405_boards.c b/hw/ppc/ppc405_boards.c index 083f12b23e..4092ebc1ab 100644 --- a/hw/ppc/ppc405_boards.c +++ b/hw/ppc/ppc405_boards.c @@ -271,25 +271,13 @@ static void boot_from_kernel(MachineState *machine, PowerPCCPU *cpu) static void ppc405_init(MachineState *machine) { Ppc405MachineState *ppc405 = PPC405_MACHINE(machine); - MachineClass *mc = MACHINE_GET_CLASS(machine); const char *kernel_filename = machine->kernel_filename; MemoryRegion *sysmem = get_system_memory(); - if (machine->ram_size != mc->default_ram_size) { - char *sz = size_to_str(mc->default_ram_size); - error_report("Invalid RAM size, should be %s", sz); - g_free(sz); - exit(EXIT_FAILURE); - } - object_initialize_child(OBJECT(machine), "soc", &ppc405->soc, TYPE_PPC405_SOC); - object_property_set_uint(OBJECT(&ppc405->soc), "ram-size", - machine->ram_size, &error_fatal); object_property_set_link(OBJECT(&ppc405->soc), "dram", OBJECT(machine->ram), &error_abort); - object_property_set_bool(OBJECT(&ppc405->soc), "dram-init", - kernel_filename != NULL, &error_abort); object_property_set_uint(OBJECT(&ppc405->soc), "sys-clk", 33333333, &error_abort); qdev_realize(DEVICE(&ppc405->soc), NULL, &error_fatal); @@ -349,6 +337,7 @@ static void ppc405_init(MachineState *machine) /* Load ELF kernel and rootfs.cpio */ } else if (kernel_filename && !machine->firmware) { + ppc4xx_sdram_ddr_enable(&ppc405->soc.sdram); boot_from_kernel(machine, &ppc405->soc.cpu); } } diff --git a/hw/ppc/ppc405_uc.c b/hw/ppc/ppc405_uc.c index 2ca42fdef6..c973cfb04e 100644 --- a/hw/ppc/ppc405_uc.c +++ b/hw/ppc/ppc405_uc.c @@ -1016,6 +1016,9 @@ static void ppc405_soc_instance_init(Object *obj) object_initialize_child(obj, "plb", &s->plb, TYPE_PPC4xx_PLB); object_initialize_child(obj, "mal", &s->mal, TYPE_PPC4xx_MAL); + + object_initialize_child(obj, "sdram", &s->sdram, TYPE_PPC4xx_SDRAM_DDR); + object_property_add_alias(obj, "dram", OBJECT(&s->sdram), "dram"); } static void ppc405_reset(void *opaque) @@ -1073,16 +1076,17 @@ static void ppc405_soc_realize(DeviceState *dev, Error **errp) qdev_get_gpio_in(DEVICE(&s->cpu), PPC40x_INPUT_CINT)); /* SDRAM controller */ - /* XXX 405EP has no ECC interrupt */ - s->ram_bases[0] = 0; - s->ram_sizes[0] = s->ram_size; - memory_region_init_alias(&s->ram_banks[0], OBJECT(s), - "ppc405.sdram0", s->dram_mr, - s->ram_bases[0], s->ram_sizes[0]); - - ppc4xx_sdram_init(env, qdev_get_gpio_in(DEVICE(&s->uic), 17), 1, - s->ram_banks, s->ram_bases, s->ram_sizes, - s->do_dram_init); + /* + * We use the 440 DDR SDRAM controller which has more regs and features + * but it's compatible enough for now + */ + object_property_set_int(OBJECT(&s->sdram), "nbanks", 2, &error_abort); + if (!ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(&s->sdram), &s->cpu, errp)) { + return; + } + /* XXX 405EP has no ECC interrupt */ + sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdram), 0, + qdev_get_gpio_in(DEVICE(&s->uic), 17)); /* External bus controller */ if (!ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(&s->ebc), &s->cpu, errp)) { @@ -1157,14 +1161,6 @@ static void ppc405_soc_realize(DeviceState *dev, Error **errp) /* Uses UIC IRQs 9, 15, 17 */ } -static Property ppc405_soc_properties[] = { - DEFINE_PROP_LINK("dram", Ppc405SoCState, dram_mr, TYPE_MEMORY_REGION, - MemoryRegion *), - DEFINE_PROP_BOOL("dram-init", Ppc405SoCState, do_dram_init, 0), - DEFINE_PROP_UINT64("ram-size", Ppc405SoCState, ram_size, 0), - DEFINE_PROP_END_OF_LIST(), -}; - static void ppc405_soc_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); @@ -1172,7 +1168,6 @@ static void ppc405_soc_class_init(ObjectClass *oc, void *data) dc->realize = ppc405_soc_realize; /* Reason: only works as part of a ppc405 board/machine */ dc->user_creatable = false; - device_class_set_props(dc, ppc405_soc_properties); } static const TypeInfo ppc405_types[] = { diff --git a/hw/ppc/ppc440.h b/hw/ppc/ppc440.h index 7cef936125..7c24db8504 100644 --- a/hw/ppc/ppc440.h +++ b/hw/ppc/ppc440.h @@ -16,10 +16,6 @@ void ppc4xx_l2sram_init(CPUPPCState *env); void ppc4xx_cpr_init(CPUPPCState *env); void ppc4xx_sdr_init(CPUPPCState *env); -void ppc440_sdram_init(CPUPPCState *env, int nbanks, - MemoryRegion *ram_memories, - hwaddr *ram_bases, hwaddr *ram_sizes, - int do_init); void ppc4xx_ahb_init(CPUPPCState *env); void ppc4xx_dma_init(CPUPPCState *env, int dcr_base); void ppc460ex_pcie_init(CPUPPCState *env); diff --git a/hw/ppc/ppc440_bamboo.c b/hw/ppc/ppc440_bamboo.c index ea945a1c99..81d71adf34 100644 --- a/hw/ppc/ppc440_bamboo.c +++ b/hw/ppc/ppc440_bamboo.c @@ -34,6 +34,8 @@ #include "hw/qdev-properties.h" #include "qapi/error.h" +#include + #define BINARY_DEVICE_TREE_FILE "bamboo.dtb" /* from u-boot */ @@ -48,22 +50,15 @@ #define PPC440EP_PCI_IO 0xe8000000 #define PPC440EP_PCI_IOLEN 0x00010000 -#define PPC440EP_SDRAM_NR_BANKS 4 - -static const ram_addr_t ppc440ep_sdram_bank_sizes[] = { - 256 * MiB, 128 * MiB, 64 * MiB, 32 * MiB, 16 * MiB, 8 * MiB, 0 -}; - static hwaddr entry; -static int bamboo_load_device_tree(hwaddr addr, - uint32_t ramsize, - hwaddr initrd_base, - hwaddr initrd_size, - const char *kernel_cmdline) +static int bamboo_load_device_tree(MachineState *machine, + hwaddr addr, + hwaddr initrd_base, + hwaddr initrd_size) { int ret = -1; - uint32_t mem_reg_property[] = { 0, 0, cpu_to_be32(ramsize) }; + uint32_t mem_reg_property[] = { 0, 0, cpu_to_be32(machine->ram_size) }; char *filename; int fdt_size; void *fdt; @@ -98,7 +93,7 @@ static int bamboo_load_device_tree(hwaddr addr, fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n"); } ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", - kernel_cmdline); + machine->kernel_cmdline); if (ret < 0) { fprintf(stderr, "couldn't set /chosen/bootargs\n"); } @@ -119,7 +114,10 @@ static int bamboo_load_device_tree(hwaddr addr, tb_freq); rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr); - g_free(fdt); + + /* Set ms->fdt for 'dumpdtb' QMP/HMP command */ + machine->fdt = fdt; + return 0; } @@ -163,14 +161,10 @@ static void main_cpu_reset(void *opaque) static void bamboo_init(MachineState *machine) { const char *kernel_filename = machine->kernel_filename; - const char *kernel_cmdline = machine->kernel_cmdline; const char *initrd_filename = machine->initrd_filename; unsigned int pci_irq_nrs[4] = { 28, 27, 26, 25 }; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *isa = g_new(MemoryRegion, 1); - MemoryRegion *ram_memories = g_new(MemoryRegion, PPC440EP_SDRAM_NR_BANKS); - hwaddr ram_bases[PPC440EP_SDRAM_NR_BANKS]; - hwaddr ram_sizes[PPC440EP_SDRAM_NR_BANKS]; PCIBus *pcibus; PowerPCCPU *cpu; CPUPPCState *env; @@ -205,15 +199,15 @@ static void bamboo_init(MachineState *machine) qdev_get_gpio_in(DEVICE(cpu), PPC40x_INPUT_CINT)); /* SDRAM controller */ - memset(ram_bases, 0, sizeof(ram_bases)); - memset(ram_sizes, 0, sizeof(ram_sizes)); - ppc4xx_sdram_banks(machine->ram, PPC440EP_SDRAM_NR_BANKS, ram_memories, - ram_bases, ram_sizes, ppc440ep_sdram_bank_sizes); + dev = qdev_new(TYPE_PPC4xx_SDRAM_DDR); + object_property_set_link(OBJECT(dev), "dram", OBJECT(machine->ram), + &error_abort); + ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(dev), cpu, &error_fatal); + object_unref(OBJECT(dev)); /* XXX 440EP's ECC interrupts are on UIC1, but we've only created UIC0. */ - ppc4xx_sdram_init(env, - qdev_get_gpio_in(uicdev, 14), - PPC440EP_SDRAM_NR_BANKS, ram_memories, - ram_bases, ram_sizes, 1); + sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(uicdev, 14)); + /* Enable SDRAM memory regions, this should be done by the firmware */ + ppc4xx_sdram_ddr_enable(PPC4xx_SDRAM_DDR(dev)); /* PCI */ dev = sysbus_create_varargs(TYPE_PPC4xx_PCI_HOST_BRIDGE, @@ -289,8 +283,8 @@ static void bamboo_init(MachineState *machine) /* If we're loading a kernel directly, we must load the device tree too. */ if (kernel_filename) { - if (bamboo_load_device_tree(FDT_ADDR, machine->ram_size, RAMDISK_ADDR, - initrd_size, kernel_cmdline) < 0) { + if (bamboo_load_device_tree(machine, FDT_ADDR, + RAMDISK_ADDR, initrd_size) < 0) { error_report("couldn't load device tree"); exit(1); } diff --git a/hw/ppc/ppc440_uc.c b/hw/ppc/ppc440_uc.c index 53e981ddf4..5fbf44009e 100644 --- a/hw/ppc/ppc440_uc.c +++ b/hw/ppc/ppc440_uc.c @@ -16,13 +16,15 @@ #include "qemu/module.h" #include "hw/irq.h" #include "exec/memory.h" -#include "hw/ppc/ppc.h" +#include "cpu.h" +#include "hw/ppc/ppc4xx.h" #include "hw/qdev-properties.h" #include "hw/pci/pci.h" #include "sysemu/block-backend.h" #include "sysemu/reset.h" #include "ppc440.h" #include "qom/object.h" +#include "trace.h" /*****************************************************************************/ /* L2 Cache as SRAM */ @@ -378,10 +380,6 @@ enum { PESDR1_RSTSTA = 0x365, }; -#define SDR0_DDR0_DDRM_ENCODE(n) ((((unsigned long)(n)) & 0x03) << 29) -#define SDR0_DDR0_DDRM_DDR1 0x20000000 -#define SDR0_DDR0_DDRM_DDR2 0x40000000 - static uint32_t dcr_read_sdr(void *opaque, int dcrn) { ppc4xx_sdr_t *sdr = opaque; @@ -482,16 +480,6 @@ void ppc4xx_sdr_init(CPUPPCState *env) /*****************************************************************************/ /* SDRAM controller */ -typedef struct ppc440_sdram_t { - uint32_t addr; - int nbanks; - MemoryRegion containers[4]; /* used for clipping */ - MemoryRegion *ram_memories; - hwaddr ram_bases[4]; - hwaddr ram_sizes[4]; - uint32_t bcr[4]; -} ppc440_sdram_t; - enum { SDRAM0_CFGADDR = 0x10, SDRAM0_CFGDATA, @@ -506,39 +494,39 @@ enum { SDRAM_PLBADDUHB = 0x50, }; -static uint32_t sdram_bcr(hwaddr ram_base, hwaddr ram_size) +static uint32_t sdram_ddr2_bcr(hwaddr ram_base, hwaddr ram_size) { uint32_t bcr; switch (ram_size) { - case (8 * MiB): + case 8 * MiB: bcr = 0xffc0; break; - case (16 * MiB): + case 16 * MiB: bcr = 0xff80; break; - case (32 * MiB): + case 32 * MiB: bcr = 0xff00; break; - case (64 * MiB): + case 64 * MiB: bcr = 0xfe00; break; - case (128 * MiB): + case 128 * MiB: bcr = 0xfc00; break; - case (256 * MiB): + case 256 * MiB: bcr = 0xf800; break; - case (512 * MiB): + case 512 * MiB: bcr = 0xf000; break; - case (1 * GiB): + case 1 * GiB: bcr = 0xe000; break; - case (2 * GiB): + case 2 * GiB: bcr = 0xc000; break; - case (4 * GiB): + case 4 * GiB: bcr = 0x8000; break; default: @@ -551,12 +539,12 @@ static uint32_t sdram_bcr(hwaddr ram_base, hwaddr ram_size) return bcr; } -static inline hwaddr sdram_base(uint32_t bcr) +static inline hwaddr sdram_ddr2_base(uint32_t bcr) { return (bcr & 0xffe00000) << 2; } -static uint64_t sdram_size(uint32_t bcr) +static uint64_t sdram_ddr2_size(uint32_t bcr) { uint64_t size; int sh; @@ -567,46 +555,66 @@ static uint64_t sdram_size(uint32_t bcr) return size; } -static void sdram_set_bcr(ppc440_sdram_t *sdram, int i, - uint32_t bcr, int enabled) +static void sdram_bank_map(Ppc4xxSdramBank *bank) { - if (sdram->bcr[i] & 1) { + memory_region_init(&bank->container, NULL, "sdram-container", bank->size); + memory_region_add_subregion(&bank->container, 0, &bank->ram); + memory_region_add_subregion(get_system_memory(), bank->base, + &bank->container); +} + +static void sdram_bank_unmap(Ppc4xxSdramBank *bank) +{ + memory_region_del_subregion(get_system_memory(), &bank->container); + memory_region_del_subregion(&bank->container, &bank->ram); + object_unparent(OBJECT(&bank->container)); +} + +static void sdram_ddr2_set_bcr(Ppc4xxSdramDdr2State *sdram, int i, + uint32_t bcr, int enabled) +{ + if (sdram->bank[i].bcr & 1) { /* First unmap RAM if enabled */ - memory_region_del_subregion(get_system_memory(), - &sdram->containers[i]); - memory_region_del_subregion(&sdram->containers[i], - &sdram->ram_memories[i]); - object_unparent(OBJECT(&sdram->containers[i])); + trace_ppc4xx_sdram_unmap(sdram_ddr2_base(sdram->bank[i].bcr), + sdram_ddr2_size(sdram->bank[i].bcr)); + sdram_bank_unmap(&sdram->bank[i]); } - sdram->bcr[i] = bcr & 0xffe0ffc1; + sdram->bank[i].bcr = bcr & 0xffe0ffc1; if (enabled && (bcr & 1)) { - memory_region_init(&sdram->containers[i], NULL, "sdram-containers", - sdram_size(bcr)); - memory_region_add_subregion(&sdram->containers[i], 0, - &sdram->ram_memories[i]); - memory_region_add_subregion(get_system_memory(), - sdram_base(bcr), - &sdram->containers[i]); + trace_ppc4xx_sdram_map(sdram_ddr2_base(bcr), sdram_ddr2_size(bcr)); + sdram_bank_map(&sdram->bank[i]); } } -static void sdram_map_bcr(ppc440_sdram_t *sdram) +static void sdram_ddr2_map_bcr(Ppc4xxSdramDdr2State *sdram) { int i; for (i = 0; i < sdram->nbanks; i++) { - if (sdram->ram_sizes[i] != 0) { - sdram_set_bcr(sdram, i, sdram_bcr(sdram->ram_bases[i], - sdram->ram_sizes[i]), 1); + if (sdram->bank[i].size) { + sdram_ddr2_set_bcr(sdram, i, + sdram_ddr2_bcr(sdram->bank[i].base, + sdram->bank[i].size), 1); } else { - sdram_set_bcr(sdram, i, 0, 0); + sdram_ddr2_set_bcr(sdram, i, 0, 0); } } } -static uint32_t dcr_read_sdram(void *opaque, int dcrn) +static void sdram_ddr2_unmap_bcr(Ppc4xxSdramDdr2State *sdram) { - ppc440_sdram_t *sdram = opaque; + int i; + + for (i = 0; i < sdram->nbanks; i++) { + if (sdram->bank[i].size) { + sdram_ddr2_set_bcr(sdram, i, sdram->bank[i].bcr & ~1, 0); + } + } +} + +static uint32_t sdram_ddr2_dcr_read(void *opaque, int dcrn) +{ + Ppc4xxSdramDdr2State *sdram = opaque; uint32_t ret = 0; switch (dcrn) { @@ -614,9 +622,9 @@ static uint32_t dcr_read_sdram(void *opaque, int dcrn) case SDRAM_R1BAS: case SDRAM_R2BAS: case SDRAM_R3BAS: - if (sdram->ram_sizes[dcrn - SDRAM_R0BAS]) { - ret = sdram_bcr(sdram->ram_bases[dcrn - SDRAM_R0BAS], - sdram->ram_sizes[dcrn - SDRAM_R0BAS]); + if (sdram->bank[dcrn - SDRAM_R0BAS].size) { + ret = sdram_ddr2_bcr(sdram->bank[dcrn - SDRAM_R0BAS].base, + sdram->bank[dcrn - SDRAM_R0BAS].size); } break; case SDRAM_CONF1HB: @@ -635,7 +643,7 @@ static uint32_t dcr_read_sdram(void *opaque, int dcrn) ret = 0x80000000; break; case 0x21: /* SDRAM_MCOPT2 */ - ret = 0x08000000; + ret = sdram->mcopt2; break; case 0x40: /* SDRAM_MB0CF */ ret = 0x00008001; @@ -657,9 +665,11 @@ static uint32_t dcr_read_sdram(void *opaque, int dcrn) return ret; } -static void dcr_write_sdram(void *opaque, int dcrn, uint32_t val) +#define SDRAM_DDR2_MCOPT2_DCEN BIT(27) + +static void sdram_ddr2_dcr_write(void *opaque, int dcrn, uint32_t val) { - ppc440_sdram_t *sdram = opaque; + Ppc4xxSdramDdr2State *sdram = opaque; switch (dcrn) { case SDRAM_R0BAS: @@ -679,6 +689,21 @@ static void dcr_write_sdram(void *opaque, int dcrn, uint32_t val) switch (sdram->addr) { case 0x00: /* B0CR */ break; + case 0x21: /* SDRAM_MCOPT2 */ + if (!(sdram->mcopt2 & SDRAM_DDR2_MCOPT2_DCEN) && + (val & SDRAM_DDR2_MCOPT2_DCEN)) { + trace_ppc4xx_sdram_enable("enable"); + /* validate all RAM mappings */ + sdram_ddr2_map_bcr(sdram); + sdram->mcopt2 |= SDRAM_DDR2_MCOPT2_DCEN; + } else if ((sdram->mcopt2 & SDRAM_DDR2_MCOPT2_DCEN) && + !(val & SDRAM_DDR2_MCOPT2_DCEN)) { + trace_ppc4xx_sdram_enable("disable"); + /* invalidate all RAM mappings */ + sdram_ddr2_unmap_bcr(sdram); + sdram->mcopt2 &= ~SDRAM_DDR2_MCOPT2_DCEN; + } + break; default: break; } @@ -688,54 +713,96 @@ static void dcr_write_sdram(void *opaque, int dcrn, uint32_t val) } } -static void sdram_reset(void *opaque) +static void ppc4xx_sdram_ddr2_reset(DeviceState *dev) { - ppc440_sdram_t *sdram = opaque; + Ppc4xxSdramDdr2State *sdram = PPC4xx_SDRAM_DDR2(dev); sdram->addr = 0; + sdram->mcopt2 = 0; } -void ppc440_sdram_init(CPUPPCState *env, int nbanks, - MemoryRegion *ram_memories, - hwaddr *ram_bases, hwaddr *ram_sizes, - int do_init) +static void ppc4xx_sdram_ddr2_realize(DeviceState *dev, Error **errp) { - ppc440_sdram_t *sdram; + Ppc4xxSdramDdr2State *s = PPC4xx_SDRAM_DDR2(dev); + Ppc4xxDcrDeviceState *dcr = PPC4xx_DCR_DEVICE(dev); + /* + * SoC also has 4 GiB but that causes problem with 32 bit + * builds (4*GiB overflows the 32 bit ram_addr_t). + */ + const ram_addr_t valid_bank_sizes[] = { + 2 * GiB, 1 * GiB, 512 * MiB, 256 * MiB, 128 * MiB, + 64 * MiB, 32 * MiB, 16 * MiB, 8 * MiB, 0 + }; - sdram = g_malloc0(sizeof(*sdram)); - sdram->nbanks = nbanks; - sdram->ram_memories = ram_memories; - memcpy(sdram->ram_bases, ram_bases, nbanks * sizeof(hwaddr)); - memcpy(sdram->ram_sizes, ram_sizes, nbanks * sizeof(hwaddr)); - qemu_register_reset(&sdram_reset, sdram); - ppc_dcr_register(env, SDRAM0_CFGADDR, - sdram, &dcr_read_sdram, &dcr_write_sdram); - ppc_dcr_register(env, SDRAM0_CFGDATA, - sdram, &dcr_read_sdram, &dcr_write_sdram); - if (do_init) { - sdram_map_bcr(sdram); + if (s->nbanks < 1 || s->nbanks > 4) { + error_setg(errp, "Invalid number of RAM banks"); + return; } + if (!s->dram_mr) { + error_setg(errp, "Missing dram memory region"); + return; + } + ppc4xx_sdram_banks(s->dram_mr, s->nbanks, s->bank, valid_bank_sizes); - ppc_dcr_register(env, SDRAM_R0BAS, - sdram, &dcr_read_sdram, &dcr_write_sdram); - ppc_dcr_register(env, SDRAM_R1BAS, - sdram, &dcr_read_sdram, &dcr_write_sdram); - ppc_dcr_register(env, SDRAM_R2BAS, - sdram, &dcr_read_sdram, &dcr_write_sdram); - ppc_dcr_register(env, SDRAM_R3BAS, - sdram, &dcr_read_sdram, &dcr_write_sdram); - ppc_dcr_register(env, SDRAM_CONF1HB, - sdram, &dcr_read_sdram, &dcr_write_sdram); - ppc_dcr_register(env, SDRAM_PLBADDULL, - sdram, &dcr_read_sdram, &dcr_write_sdram); - ppc_dcr_register(env, SDRAM_CONF1LL, - sdram, &dcr_read_sdram, &dcr_write_sdram); - ppc_dcr_register(env, SDRAM_CONFPATHB, - sdram, &dcr_read_sdram, &dcr_write_sdram); - ppc_dcr_register(env, SDRAM_PLBADDUHB, - sdram, &dcr_read_sdram, &dcr_write_sdram); + ppc4xx_dcr_register(dcr, SDRAM0_CFGADDR, + s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write); + ppc4xx_dcr_register(dcr, SDRAM0_CFGDATA, + s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write); + + ppc4xx_dcr_register(dcr, SDRAM_R0BAS, + s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write); + ppc4xx_dcr_register(dcr, SDRAM_R1BAS, + s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write); + ppc4xx_dcr_register(dcr, SDRAM_R2BAS, + s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write); + ppc4xx_dcr_register(dcr, SDRAM_R3BAS, + s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write); + ppc4xx_dcr_register(dcr, SDRAM_CONF1HB, + s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write); + ppc4xx_dcr_register(dcr, SDRAM_PLBADDULL, + s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write); + ppc4xx_dcr_register(dcr, SDRAM_CONF1LL, + s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write); + ppc4xx_dcr_register(dcr, SDRAM_CONFPATHB, + s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write); + ppc4xx_dcr_register(dcr, SDRAM_PLBADDUHB, + s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write); } +static Property ppc4xx_sdram_ddr2_props[] = { + DEFINE_PROP_LINK("dram", Ppc4xxSdramDdr2State, dram_mr, TYPE_MEMORY_REGION, + MemoryRegion *), + DEFINE_PROP_UINT32("nbanks", Ppc4xxSdramDdr2State, nbanks, 4), + DEFINE_PROP_END_OF_LIST(), +}; + +static void ppc4xx_sdram_ddr2_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = ppc4xx_sdram_ddr2_realize; + dc->reset = ppc4xx_sdram_ddr2_reset; + /* Reason: only works as function of a ppc4xx SoC */ + dc->user_creatable = false; + device_class_set_props(dc, ppc4xx_sdram_ddr2_props); +} + +void ppc4xx_sdram_ddr2_enable(Ppc4xxSdramDdr2State *s) +{ + sdram_ddr2_dcr_write(s, SDRAM0_CFGADDR, 0x21); + sdram_ddr2_dcr_write(s, SDRAM0_CFGDATA, 0x08000000); +} + +static const TypeInfo ppc4xx_types[] = { + { + .name = TYPE_PPC4xx_SDRAM_DDR2, + .parent = TYPE_PPC4xx_DCR_DEVICE, + .instance_size = sizeof(Ppc4xxSdramDdr2State), + .class_init = ppc4xx_sdram_ddr2_class_init, + } +}; +DEFINE_TYPES(ppc4xx_types) + /*****************************************************************************/ /* PLB to AHB bridge */ enum { diff --git a/hw/ppc/ppc4xx_devs.c b/hw/ppc/ppc4xx_devs.c index ce38ae65e6..12af90f244 100644 --- a/hw/ppc/ppc4xx_devs.c +++ b/hw/ppc/ppc4xx_devs.c @@ -38,28 +38,6 @@ /*****************************************************************************/ /* SDRAM controller */ -typedef struct ppc4xx_sdram_t ppc4xx_sdram_t; -struct ppc4xx_sdram_t { - uint32_t addr; - int nbanks; - MemoryRegion containers[4]; /* used for clipping */ - MemoryRegion *ram_memories; - hwaddr ram_bases[4]; - hwaddr ram_sizes[4]; - uint32_t besr0; - uint32_t besr1; - uint32_t bear; - uint32_t cfg; - uint32_t status; - uint32_t rtr; - uint32_t pmit; - uint32_t bcr[4]; - uint32_t tr; - uint32_t ecccfg; - uint32_t eccesr; - qemu_irq irq; -}; - enum { SDRAM0_CFGADDR = 0x010, SDRAM0_CFGDATA = 0x011, @@ -70,37 +48,37 @@ enum { * there are type inconsistencies, mixing hwaddr, target_ulong * and uint32_t */ -static uint32_t sdram_bcr(hwaddr ram_base, hwaddr ram_size) +static uint32_t sdram_ddr_bcr(hwaddr ram_base, hwaddr ram_size) { uint32_t bcr; switch (ram_size) { case 4 * MiB: - bcr = 0x00000000; + bcr = 0; break; case 8 * MiB: - bcr = 0x00020000; + bcr = 0x20000; break; case 16 * MiB: - bcr = 0x00040000; + bcr = 0x40000; break; case 32 * MiB: - bcr = 0x00060000; + bcr = 0x60000; break; case 64 * MiB: - bcr = 0x00080000; + bcr = 0x80000; break; case 128 * MiB: - bcr = 0x000A0000; + bcr = 0xA0000; break; case 256 * MiB: - bcr = 0x000C0000; + bcr = 0xC0000; break; default: qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid RAM size 0x%" HWADDR_PRIx "\n", __func__, ram_size); - return 0x00000000; + return 0; } bcr |= ram_base & 0xFF800000; bcr |= 1; @@ -108,12 +86,12 @@ static uint32_t sdram_bcr(hwaddr ram_base, hwaddr ram_size) return bcr; } -static inline hwaddr sdram_base(uint32_t bcr) +static inline hwaddr sdram_ddr_base(uint32_t bcr) { return bcr & 0xFF800000; } -static target_ulong sdram_size(uint32_t bcr) +static target_ulong sdram_ddr_size(uint32_t bcr) { target_ulong size; int sh; @@ -128,64 +106,63 @@ static target_ulong sdram_size(uint32_t bcr) return size; } -static void sdram_set_bcr(ppc4xx_sdram_t *sdram, int i, - uint32_t bcr, int enabled) +static void sdram_ddr_set_bcr(Ppc4xxSdramDdrState *sdram, int i, + uint32_t bcr, int enabled) { - if (sdram->bcr[i] & 0x00000001) { + if (sdram->bank[i].bcr & 1) { /* Unmap RAM */ - trace_ppc4xx_sdram_unmap(sdram_base(sdram->bcr[i]), - sdram_size(sdram->bcr[i])); + trace_ppc4xx_sdram_unmap(sdram_ddr_base(sdram->bank[i].bcr), + sdram_ddr_size(sdram->bank[i].bcr)); memory_region_del_subregion(get_system_memory(), - &sdram->containers[i]); - memory_region_del_subregion(&sdram->containers[i], - &sdram->ram_memories[i]); - object_unparent(OBJECT(&sdram->containers[i])); + &sdram->bank[i].container); + memory_region_del_subregion(&sdram->bank[i].container, + &sdram->bank[i].ram); + object_unparent(OBJECT(&sdram->bank[i].container)); } - sdram->bcr[i] = bcr & 0xFFDEE001; - if (enabled && (bcr & 0x00000001)) { - trace_ppc4xx_sdram_map(sdram_base(bcr), sdram_size(bcr)); - memory_region_init(&sdram->containers[i], NULL, "sdram-containers", - sdram_size(bcr)); - memory_region_add_subregion(&sdram->containers[i], 0, - &sdram->ram_memories[i]); + sdram->bank[i].bcr = bcr & 0xFFDEE001; + if (enabled && (bcr & 1)) { + trace_ppc4xx_sdram_map(sdram_ddr_base(bcr), sdram_ddr_size(bcr)); + memory_region_init(&sdram->bank[i].container, NULL, "sdram-container", + sdram_ddr_size(bcr)); + memory_region_add_subregion(&sdram->bank[i].container, 0, + &sdram->bank[i].ram); memory_region_add_subregion(get_system_memory(), - sdram_base(bcr), - &sdram->containers[i]); + sdram_ddr_base(bcr), + &sdram->bank[i].container); } } -static void sdram_map_bcr(ppc4xx_sdram_t *sdram) +static void sdram_ddr_map_bcr(Ppc4xxSdramDdrState *sdram) { int i; for (i = 0; i < sdram->nbanks; i++) { - if (sdram->ram_sizes[i] != 0) { - sdram_set_bcr(sdram, i, sdram_bcr(sdram->ram_bases[i], - sdram->ram_sizes[i]), 1); + if (sdram->bank[i].size != 0) { + sdram_ddr_set_bcr(sdram, i, sdram_ddr_bcr(sdram->bank[i].base, + sdram->bank[i].size), 1); } else { - sdram_set_bcr(sdram, i, 0x00000000, 0); + sdram_ddr_set_bcr(sdram, i, 0, 0); } } } -static void sdram_unmap_bcr(ppc4xx_sdram_t *sdram) +static void sdram_ddr_unmap_bcr(Ppc4xxSdramDdrState *sdram) { int i; for (i = 0; i < sdram->nbanks; i++) { - trace_ppc4xx_sdram_unmap(sdram_base(sdram->bcr[i]), - sdram_size(sdram->bcr[i])); + trace_ppc4xx_sdram_unmap(sdram_ddr_base(sdram->bank[i].bcr), + sdram_ddr_size(sdram->bank[i].bcr)); memory_region_del_subregion(get_system_memory(), - &sdram->ram_memories[i]); + &sdram->bank[i].ram); } } -static uint32_t dcr_read_sdram(void *opaque, int dcrn) +static uint32_t sdram_ddr_dcr_read(void *opaque, int dcrn) { - ppc4xx_sdram_t *sdram; + Ppc4xxSdramDdrState *sdram = opaque; uint32_t ret; - sdram = opaque; switch (dcrn) { case SDRAM0_CFGADDR: ret = sdram->addr; @@ -214,16 +191,16 @@ static uint32_t dcr_read_sdram(void *opaque, int dcrn) ret = sdram->pmit; break; case 0x40: /* SDRAM_B0CR */ - ret = sdram->bcr[0]; + ret = sdram->bank[0].bcr; break; case 0x44: /* SDRAM_B1CR */ - ret = sdram->bcr[1]; + ret = sdram->bank[1].bcr; break; case 0x48: /* SDRAM_B2CR */ - ret = sdram->bcr[2]; + ret = sdram->bank[2].bcr; break; case 0x4C: /* SDRAM_B3CR */ - ret = sdram->bcr[3]; + ret = sdram->bank[3].bcr; break; case 0x80: /* SDRAM_TR */ ret = -1; /* ? */ @@ -241,18 +218,17 @@ static uint32_t dcr_read_sdram(void *opaque, int dcrn) break; default: /* Avoid gcc warning */ - ret = 0x00000000; + ret = 0; break; } return ret; } -static void dcr_write_sdram(void *opaque, int dcrn, uint32_t val) +static void sdram_ddr_dcr_write(void *opaque, int dcrn, uint32_t val) { - ppc4xx_sdram_t *sdram; + Ppc4xxSdramDdrState *sdram = opaque; - sdram = opaque; switch (dcrn) { case SDRAM0_CFGADDR: sdram->addr = val; @@ -273,12 +249,12 @@ static void dcr_write_sdram(void *opaque, int dcrn, uint32_t val) if (!(sdram->cfg & 0x80000000) && (val & 0x80000000)) { trace_ppc4xx_sdram_enable("enable"); /* validate all RAM mappings */ - sdram_map_bcr(sdram); + sdram_ddr_map_bcr(sdram); sdram->status &= ~0x80000000; } else if ((sdram->cfg & 0x80000000) && !(val & 0x80000000)) { trace_ppc4xx_sdram_enable("disable"); /* invalidate all RAM mappings */ - sdram_unmap_bcr(sdram); + sdram_ddr_unmap_bcr(sdram); sdram->status |= 0x80000000; } if (!(sdram->cfg & 0x40000000) && (val & 0x40000000)) { @@ -298,16 +274,16 @@ static void dcr_write_sdram(void *opaque, int dcrn, uint32_t val) sdram->pmit = (val & 0xF8000000) | 0x07C00000; break; case 0x40: /* SDRAM_B0CR */ - sdram_set_bcr(sdram, 0, val, sdram->cfg & 0x80000000); + sdram_ddr_set_bcr(sdram, 0, val, sdram->cfg & 0x80000000); break; case 0x44: /* SDRAM_B1CR */ - sdram_set_bcr(sdram, 1, val, sdram->cfg & 0x80000000); + sdram_ddr_set_bcr(sdram, 1, val, sdram->cfg & 0x80000000); break; case 0x48: /* SDRAM_B2CR */ - sdram_set_bcr(sdram, 2, val, sdram->cfg & 0x80000000); + sdram_ddr_set_bcr(sdram, 2, val, sdram->cfg & 0x80000000); break; case 0x4C: /* SDRAM_B3CR */ - sdram_set_bcr(sdram, 3, val, sdram->cfg & 0x80000000); + sdram_ddr_set_bcr(sdram, 3, val, sdram->cfg & 0x80000000); break; case 0x80: /* SDRAM_TR */ sdram->tr = val & 0x018FC01F; @@ -331,52 +307,73 @@ static void dcr_write_sdram(void *opaque, int dcrn, uint32_t val) } } -static void sdram_reset(void *opaque) +static void ppc4xx_sdram_ddr_reset(DeviceState *dev) { - ppc4xx_sdram_t *sdram; + Ppc4xxSdramDdrState *sdram = PPC4xx_SDRAM_DDR(dev); - sdram = opaque; - sdram->addr = 0x00000000; - sdram->bear = 0x00000000; - sdram->besr0 = 0x00000000; /* No error */ - sdram->besr1 = 0x00000000; /* No error */ - sdram->cfg = 0x00000000; - sdram->ecccfg = 0x00000000; /* No ECC */ - sdram->eccesr = 0x00000000; /* No error */ + sdram->addr = 0; + sdram->bear = 0; + sdram->besr0 = 0; /* No error */ + sdram->besr1 = 0; /* No error */ + sdram->cfg = 0; + sdram->ecccfg = 0; /* No ECC */ + sdram->eccesr = 0; /* No error */ sdram->pmit = 0x07C00000; sdram->rtr = 0x05F00000; sdram->tr = 0x00854009; /* We pre-initialize RAM banks */ - sdram->status = 0x00000000; + sdram->status = 0; sdram->cfg = 0x00800000; } -void ppc4xx_sdram_init(CPUPPCState *env, qemu_irq irq, int nbanks, - MemoryRegion *ram_memories, - hwaddr *ram_bases, - hwaddr *ram_sizes, - int do_init) +static void ppc4xx_sdram_ddr_realize(DeviceState *dev, Error **errp) { - ppc4xx_sdram_t *sdram; + Ppc4xxSdramDdrState *s = PPC4xx_SDRAM_DDR(dev); + Ppc4xxDcrDeviceState *dcr = PPC4xx_DCR_DEVICE(dev); + const ram_addr_t valid_bank_sizes[] = { + 256 * MiB, 128 * MiB, 64 * MiB, 32 * MiB, 16 * MiB, 8 * MiB, 4 * MiB, 0 + }; - sdram = g_new0(ppc4xx_sdram_t, 1); - sdram->irq = irq; - sdram->nbanks = nbanks; - sdram->ram_memories = ram_memories; - memset(sdram->ram_bases, 0, 4 * sizeof(hwaddr)); - memcpy(sdram->ram_bases, ram_bases, - nbanks * sizeof(hwaddr)); - memset(sdram->ram_sizes, 0, 4 * sizeof(hwaddr)); - memcpy(sdram->ram_sizes, ram_sizes, - nbanks * sizeof(hwaddr)); - qemu_register_reset(&sdram_reset, sdram); - ppc_dcr_register(env, SDRAM0_CFGADDR, - sdram, &dcr_read_sdram, &dcr_write_sdram); - ppc_dcr_register(env, SDRAM0_CFGDATA, - sdram, &dcr_read_sdram, &dcr_write_sdram); - if (do_init) { - sdram_map_bcr(sdram); + if (s->nbanks < 1 || s->nbanks > 4) { + error_setg(errp, "Invalid number of RAM banks"); + return; } + if (!s->dram_mr) { + error_setg(errp, "Missing dram memory region"); + return; + } + ppc4xx_sdram_banks(s->dram_mr, s->nbanks, s->bank, valid_bank_sizes); + + sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq); + + ppc4xx_dcr_register(dcr, SDRAM0_CFGADDR, + s, &sdram_ddr_dcr_read, &sdram_ddr_dcr_write); + ppc4xx_dcr_register(dcr, SDRAM0_CFGDATA, + s, &sdram_ddr_dcr_read, &sdram_ddr_dcr_write); +} + +static Property ppc4xx_sdram_ddr_props[] = { + DEFINE_PROP_LINK("dram", Ppc4xxSdramDdrState, dram_mr, TYPE_MEMORY_REGION, + MemoryRegion *), + DEFINE_PROP_UINT32("nbanks", Ppc4xxSdramDdrState, nbanks, 4), + DEFINE_PROP_END_OF_LIST(), +}; + +static void ppc4xx_sdram_ddr_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = ppc4xx_sdram_ddr_realize; + dc->reset = ppc4xx_sdram_ddr_reset; + /* Reason: only works as function of a ppc4xx SoC */ + dc->user_creatable = false; + device_class_set_props(dc, ppc4xx_sdram_ddr_props); +} + +void ppc4xx_sdram_ddr_enable(Ppc4xxSdramDdrState *s) +{ + sdram_ddr_dcr_write(s, SDRAM0_CFGADDR, 0x20); + sdram_ddr_dcr_write(s, SDRAM0_CFGDATA, 0x80000000); } /* @@ -390,8 +387,7 @@ void ppc4xx_sdram_init(CPUPPCState *env, qemu_irq irq, int nbanks, * sizes varies by SoC. */ void ppc4xx_sdram_banks(MemoryRegion *ram, int nr_banks, - MemoryRegion ram_memories[], - hwaddr ram_bases[], hwaddr ram_sizes[], + Ppc4xxSdramBank ram_banks[], const ram_addr_t sdram_bank_sizes[]) { ram_addr_t size_left = memory_region_size(ram); @@ -406,13 +402,13 @@ void ppc4xx_sdram_banks(MemoryRegion *ram, int nr_banks, if (bank_size <= size_left) { char name[32]; - ram_bases[i] = base; - ram_sizes[i] = bank_size; + ram_banks[i].base = base; + ram_banks[i].size = bank_size; base += bank_size; size_left -= bank_size; snprintf(name, sizeof(name), "ppc4xx.sdram%d", i); - memory_region_init_alias(&ram_memories[i], NULL, name, ram, - ram_bases[i], ram_sizes[i]); + memory_region_init_alias(&ram_banks[i].ram, NULL, name, ram, + ram_banks[i].base, ram_banks[i].size); break; } } @@ -967,6 +963,11 @@ static void ppc4xx_dcr_class_init(ObjectClass *oc, void *data) static const TypeInfo ppc4xx_types[] = { { + .name = TYPE_PPC4xx_SDRAM_DDR, + .parent = TYPE_PPC4xx_DCR_DEVICE, + .instance_size = sizeof(Ppc4xxSdramDdrState), + .class_init = ppc4xx_sdram_ddr_class_init, + }, { .name = TYPE_PPC4xx_MAL, .parent = TYPE_PPC4xx_DCR_DEVICE, .instance_size = sizeof(Ppc4xxMalState), diff --git a/hw/ppc/sam460ex.c b/hw/ppc/sam460ex.c index 850bb3b817..4a22ce3761 100644 --- a/hw/ppc/sam460ex.c +++ b/hw/ppc/sam460ex.c @@ -73,14 +73,6 @@ #define OPB_FREQ 115000000 #define EBC_FREQ 115000000 #define UART_FREQ 11059200 -#define SDRAM_NR_BANKS 4 - -/* The SoC could also handle 4 GiB but firmware does not work with that. */ -/* Maybe it overflows a signed 32 bit number somewhere? */ -static const ram_addr_t ppc460ex_sdram_bank_sizes[] = { - 2 * GiB, 1 * GiB, 512 * MiB, 256 * MiB, 128 * MiB, 64 * MiB, - 32 * MiB, 0 -}; struct boot_info { uint32_t dt_base; @@ -131,13 +123,12 @@ static int sam460ex_load_uboot(void) return 0; } -static int sam460ex_load_device_tree(hwaddr addr, - uint32_t ramsize, +static int sam460ex_load_device_tree(MachineState *machine, + hwaddr addr, hwaddr initrd_base, - hwaddr initrd_size, - const char *kernel_cmdline) + hwaddr initrd_size) { - uint32_t mem_reg_property[] = { 0, 0, cpu_to_be32(ramsize) }; + uint32_t mem_reg_property[] = { 0, 0, cpu_to_be32(machine->ram_size) }; char *filename; int fdt_size; void *fdt; @@ -171,7 +162,8 @@ static int sam460ex_load_device_tree(hwaddr addr, qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end", (initrd_base + initrd_size)); - qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", kernel_cmdline); + qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", + machine->kernel_cmdline); /* Copy data from the host device tree into the guest. Since the guest can * directly access the timebase without host involvement, we must expose @@ -208,7 +200,9 @@ static int sam460ex_load_device_tree(hwaddr addr, EBC_FREQ); rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr); - g_free(fdt); + + /* Set machine->fdt for 'dumpdtb' QMP/HMP command */ + machine->fdt = fdt; return fdt_size; } @@ -274,9 +268,6 @@ static void sam460ex_init(MachineState *machine) { MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *isa = g_new(MemoryRegion, 1); - MemoryRegion *ram_memories = g_new(MemoryRegion, SDRAM_NR_BANKS); - hwaddr ram_bases[SDRAM_NR_BANKS] = {0}; - hwaddr ram_sizes[SDRAM_NR_BANKS] = {0}; MemoryRegion *l2cache_ram = g_new(MemoryRegion, 1); DeviceState *uic[4]; int i; @@ -343,22 +334,37 @@ static void sam460ex_init(MachineState *machine) } /* SDRAM controller */ - /* put all RAM on first bank because board has one slot - * and firmware only checks that */ - ppc4xx_sdram_banks(machine->ram, 1, ram_memories, ram_bases, ram_sizes, - ppc460ex_sdram_bank_sizes); - + /* The SoC could also handle 4 GiB but firmware does not work with that. */ + if (machine->ram_size > 2 * GiB) { + error_report("Memory over 2 GiB is not supported"); + exit(1); + } + /* Firmware needs at least 64 MiB */ + if (machine->ram_size < 64 * MiB) { + error_report("Memory below 64 MiB is not supported"); + exit(1); + } + dev = qdev_new(TYPE_PPC4xx_SDRAM_DDR2); + object_property_set_link(OBJECT(dev), "dram", OBJECT(machine->ram), + &error_abort); + /* + * Put all RAM on first bank because board has one slot + * and firmware only checks that + */ + object_property_set_int(OBJECT(dev), "nbanks", 1, &error_abort); + ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(dev), cpu, &error_fatal); + object_unref(OBJECT(dev)); /* FIXME: does 460EX have ECC interrupts? */ - ppc440_sdram_init(env, SDRAM_NR_BANKS, ram_memories, - ram_bases, ram_sizes, 1); + /* Enable SDRAM memory regions as we may boot without firmware */ + ppc4xx_sdram_ddr2_enable(PPC4xx_SDRAM_DDR2(dev)); /* IIC controllers and devices */ dev = sysbus_create_simple(TYPE_PPC4xx_I2C, 0x4ef600700, qdev_get_gpio_in(uic[0], 2)); i2c = PPC4xx_I2C(dev)->bus; /* SPD EEPROM on RAM module */ - spd_data = spd_data_generate(ram_sizes[0] < 128 * MiB ? DDR : DDR2, - ram_sizes[0]); + spd_data = spd_data_generate(machine->ram_size < 128 * MiB ? DDR : DDR2, + machine->ram_size); spd_data[20] = 4; /* SO-DIMM module */ smbus_eeprom_init_one(i2c, 0x50, spd_data); /* RTC */ @@ -496,9 +502,8 @@ static void sam460ex_init(MachineState *machine) if (machine->kernel_filename) { int dt_size; - dt_size = sam460ex_load_device_tree(FDT_ADDR, machine->ram_size, - RAMDISK_ADDR, initrd_size, - machine->kernel_cmdline); + dt_size = sam460ex_load_device_tree(machine, FDT_ADDR, + RAMDISK_ADDR, initrd_size); boot_info->dt_base = FDT_ADDR; boot_info->dt_size = dt_size; diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 8bbaf4f8a4..f79ac85ca1 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1713,6 +1713,9 @@ static void spapr_machine_reset(MachineState *machine) spapr->fdt_initial_size = spapr->fdt_size; spapr->fdt_blob = fdt; + /* Set machine->fdt for 'dumpdtb' QMP/HMP command */ + machine->fdt = fdt; + /* Set up the entry state */ first_ppc_cpu->env.gpr[5] = 0; diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index a8d4a6bcf0..891206e893 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -1256,6 +1256,14 @@ target_ulong do_client_architecture_support(PowerPCCPU *cpu, spapr->fdt_initial_size = spapr->fdt_size; spapr->fdt_blob = fdt; + /* + * Set the machine->fdt pointer again since we just freed + * it above (by freeing spapr->fdt_blob). We set this + * pointer to enable support for the 'dumpdtb' QMP/HMP + * command. + */ + MACHINE(spapr)->fdt = fdt; + return H_SUCCESS; } diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 57c8a4f085..7b7618d5da 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -2045,7 +2045,7 @@ static int spapr_phb_children_reset(Object *child, void *opaque) DeviceState *dev = (DeviceState *) object_dynamic_cast(child, TYPE_DEVICE); if (dev) { - device_legacy_reset(dev); + device_cold_reset(dev); } return 0; diff --git a/hw/ppc/virtex_ml507.c b/hw/ppc/virtex_ml507.c index 493ea0c19f..13cace229b 100644 --- a/hw/ppc/virtex_ml507.c +++ b/hw/ppc/virtex_ml507.c @@ -45,6 +45,8 @@ #include "hw/qdev-properties.h" #include "ppc405.h" +#include + #define EPAPR_MAGIC (0x45504150) #define FLASH_SIZE (16 * MiB) @@ -144,11 +146,10 @@ static void main_cpu_reset(void *opaque) } #define BINARY_DEVICE_TREE_FILE "virtex-ml507.dtb" -static int xilinx_load_device_tree(hwaddr addr, - uint32_t ramsize, - hwaddr initrd_base, - hwaddr initrd_size, - const char *kernel_cmdline) +static int xilinx_load_device_tree(MachineState *machine, + hwaddr addr, + hwaddr initrd_base, + hwaddr initrd_size) { char *path; int fdt_size; @@ -190,18 +191,21 @@ static int xilinx_load_device_tree(hwaddr addr, error_report("couldn't set /chosen/linux,initrd-end"); } - r = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", kernel_cmdline); + r = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", + machine->kernel_cmdline); if (r < 0) fprintf(stderr, "couldn't set /chosen/bootargs\n"); cpu_physical_memory_write(addr, fdt, fdt_size); - g_free(fdt); + + /* Set machine->fdt for 'dumpdtb' QMP/HMP command */ + machine->fdt = fdt; + return fdt_size; } static void virtex_init(MachineState *machine) { const char *kernel_filename = machine->kernel_filename; - const char *kernel_cmdline = machine->kernel_cmdline; hwaddr initrd_base = 0; int initrd_size = 0; MemoryRegion *address_space_mem = get_system_memory(); @@ -294,9 +298,8 @@ static void virtex_init(MachineState *machine) boot_info.fdt = high + (8192 * 2); boot_info.fdt &= ~8191; - xilinx_load_device_tree(boot_info.fdt, machine->ram_size, - initrd_base, initrd_size, - kernel_cmdline); + xilinx_load_device_tree(machine, boot_info.fdt, + initrd_base, initrd_size); } env->load_info = &boot_info; } diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index e4c814a3ea..b139824aab 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -634,6 +634,9 @@ static void sifive_u_machine_init(MachineState *machine) start_addr_hi32 = (uint64_t)start_addr >> 32; } + /* Set machine->fdt for 'dumpdtb' QMP/HMP command */ + machine->fdt = s->fdt; + /* reset vector */ uint32_t reset_vec[12] = { s->msel, /* MSEL pin state */ diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index 5ba34543c8..1e1d752c00 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -40,6 +40,8 @@ #include "sysemu/device_tree.h" #include "sysemu/sysemu.h" +#include + static const MemMapEntry spike_memmap[] = { [SPIKE_MROM] = { 0x1000, 0xf000 }, [SPIKE_HTIF] = { 0x1000000, 0x1000 }, @@ -304,6 +306,10 @@ static void spike_board_init(MachineState *machine) /* Compute the fdt load address in dram */ fdt_load_addr = riscv_load_fdt(memmap[SPIKE_DRAM].base, machine->ram_size, s->fdt); + + /* Set machine->fdt for 'dumpdtb' QMP/HMP command */ + machine->fdt = s->fdt; + /* load the reset vector */ riscv_setup_rom_reset_vec(machine, &s->soc[0], memmap[SPIKE_DRAM].base, memmap[SPIKE_MROM].base, diff --git a/include/hw/ppc/ppc4xx.h b/include/hw/ppc/ppc4xx.h index a1781afa8e..10c6dd535f 100644 --- a/include/hw/ppc/ppc4xx.h +++ b/include/hw/ppc/ppc4xx.h @@ -29,16 +29,17 @@ #include "exec/memory.h" #include "hw/sysbus.h" -void ppc4xx_sdram_banks(MemoryRegion *ram, int nr_banks, - MemoryRegion ram_memories[], - hwaddr ram_bases[], hwaddr ram_sizes[], - const ram_addr_t sdram_bank_sizes[]); +typedef struct { + MemoryRegion ram; + MemoryRegion container; /* used for clipping */ + hwaddr base; + hwaddr size; + uint32_t bcr; +} Ppc4xxSdramBank; -void ppc4xx_sdram_init (CPUPPCState *env, qemu_irq irq, int nbanks, - MemoryRegion ram_memories[], - hwaddr *ram_bases, - hwaddr *ram_sizes, - int do_init); +void ppc4xx_sdram_banks(MemoryRegion *ram, int nr_banks, + Ppc4xxSdramBank ram_banks[], + const ram_addr_t sdram_bank_sizes[]); #define TYPE_PPC4xx_PCI_HOST_BRIDGE "ppc4xx-pcihost" @@ -109,4 +110,50 @@ struct Ppc4xxEbcState { uint32_t cfg; }; +/* SDRAM DDR controller */ +#define SDR0_DDR0_DDRM_ENCODE(n) ((((unsigned long)(n)) & 0x03) << 29) +#define SDR0_DDR0_DDRM_DDR1 0x20000000 +#define SDR0_DDR0_DDRM_DDR2 0x40000000 + +#define TYPE_PPC4xx_SDRAM_DDR "ppc4xx-sdram-ddr" +OBJECT_DECLARE_SIMPLE_TYPE(Ppc4xxSdramDdrState, PPC4xx_SDRAM_DDR); +struct Ppc4xxSdramDdrState { + Ppc4xxDcrDeviceState parent_obj; + + MemoryRegion *dram_mr; + uint32_t nbanks; /* Banks to use from 4, e.g. when board has less slots */ + Ppc4xxSdramBank bank[4]; + qemu_irq irq; + + uint32_t addr; + uint32_t besr0; + uint32_t besr1; + uint32_t bear; + uint32_t cfg; + uint32_t status; + uint32_t rtr; + uint32_t pmit; + uint32_t tr; + uint32_t ecccfg; + uint32_t eccesr; +}; + +void ppc4xx_sdram_ddr_enable(Ppc4xxSdramDdrState *s); + +/* SDRAM DDR2 controller */ +#define TYPE_PPC4xx_SDRAM_DDR2 "ppc4xx-sdram-ddr2" +OBJECT_DECLARE_SIMPLE_TYPE(Ppc4xxSdramDdr2State, PPC4xx_SDRAM_DDR2); +struct Ppc4xxSdramDdr2State { + Ppc4xxDcrDeviceState parent_obj; + + MemoryRegion *dram_mr; + uint32_t nbanks; /* Banks to use from 4, e.g. when board has less slots */ + Ppc4xxSdramBank bank[4]; + + uint32_t addr; + uint32_t mcopt2; +}; + +void ppc4xx_sdram_ddr2_enable(Ppc4xxSdramDdr2State *s); + #endif /* PPC4XX_H */ diff --git a/include/sysemu/device_tree.h b/include/sysemu/device_tree.h index ef060a9759..e7c5441f56 100644 --- a/include/sysemu/device_tree.h +++ b/include/sysemu/device_tree.h @@ -136,6 +136,7 @@ int qemu_fdt_add_path(void *fdt, const char *path); } while (0) void qemu_fdt_dumpdtb(void *fdt, int size); +void hmp_dumpdtb(Monitor *mon, const QDict *qdict); /** * qemu_fdt_setprop_sized_cells_from_array: diff --git a/monitor/misc.c b/monitor/misc.c index 6436a8786b..205487e2b9 100644 --- a/monitor/misc.c +++ b/monitor/misc.c @@ -49,6 +49,7 @@ #include "sysemu/blockdev.h" #include "sysemu/sysemu.h" #include "sysemu/tpm.h" +#include "sysemu/device_tree.h" #include "qapi/qmp/qdict.h" #include "qapi/qmp/qerror.h" #include "qapi/qmp/qstring.h" diff --git a/qapi/machine.json b/qapi/machine.json index abb2f48808..b9228a5e46 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -1664,3 +1664,21 @@ '*size': 'size', '*max-size': 'size', '*slots': 'uint64' } } + +## +# @dumpdtb: +# +# Save the FDT in dtb format. +# +# @filename: name of the dtb file to be created +# +# Since: 7.2 +# +# Example: +# {"execute": "dumpdtb"} +# "arguments": { "filename": "fdt.dtb" } } +# +## +{ 'command': 'dumpdtb', + 'data': { 'filename': 'str' }, + 'if': 'CONFIG_FDT' } diff --git a/softmmu/device_tree.c b/softmmu/device_tree.c index 6ca3fad285..ce74f3d48d 100644 --- a/softmmu/device_tree.c +++ b/softmmu/device_tree.c @@ -26,6 +26,9 @@ #include "hw/loader.h" #include "hw/boards.h" #include "qemu/config-file.h" +#include "qapi/qapi-commands-machine.h" +#include "qapi/qmp/qdict.h" +#include "monitor/hmp.h" #include @@ -643,3 +646,37 @@ out: g_free(propcells); return ret; } + +void qmp_dumpdtb(const char *filename, Error **errp) +{ + g_autoptr(GError) err = NULL; + uint32_t size; + + if (!current_machine->fdt) { + error_setg(errp, "This machine doesn't have a FDT"); + return; + } + + size = fdt_totalsize(current_machine->fdt); + + g_assert(size > 0); + + if (!g_file_set_contents(filename, current_machine->fdt, size, &err)) { + error_setg(errp, "Error saving FDT to file %s: %s", + filename, err->message); + } +} + +void hmp_dumpdtb(Monitor *mon, const QDict *qdict) +{ + const char *filename = qdict_get_str(qdict, "filename"); + Error *local_err = NULL; + + qmp_dumpdtb(filename, &local_err); + + if (hmp_handle_error(mon, local_err)) { + return; + } + + info_report("dtb dumped to %s", filename); +} diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 214acf5ac4..43f2480e94 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -1247,6 +1247,12 @@ static void powerpc_excp_booke(PowerPCCPU *cpu, int excp) case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable/VPU */ env->spr[SPR_BOOKE_ESR] = ESR_SPV; break; + case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */ + break; + case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */ + srr0 = SPR_BOOKE_CSRR0; + srr1 = SPR_BOOKE_CSRR1; + break; case POWERPC_EXCP_RESET: /* System reset exception */ if (FIELD_EX64(env->msr, MSR, POW)) { cpu_abort(cs, "Trying to deliver power-saving system reset " diff --git a/target/ppc/translate/vsx-impl.c.inc b/target/ppc/translate/vsx-impl.c.inc index 7acdbceec4..e6e5c45ffd 100644 --- a/target/ppc/translate/vsx-impl.c.inc +++ b/target/ppc/translate/vsx-impl.c.inc @@ -810,7 +810,6 @@ static void gen_##name(DisasContext *ctx) \ gen_helper_##name(ignored, cpu_env, xt, xa, xb); \ tcg_temp_free_i32(ignored); \ } \ - gen_helper_float_check_status(cpu_env); \ tcg_temp_free_ptr(xt); \ tcg_temp_free_ptr(xa); \ tcg_temp_free_ptr(xb); \