diff options
author | Stefan Hajnoczi <stefanha@redhat.com> | 2022-10-18 11:13:57 -0400 |
---|---|---|
committer | Stefan Hajnoczi <stefanha@redhat.com> | 2022-10-18 11:13:58 -0400 |
commit | 2c65091fd9d387b8dca8115dbdd9c3c61f658a9e (patch) | |
tree | 17268b797cd7833332b5b1504c0392daacbd1d39 /hw | |
parent | 8823ef1336d6c4af1a6ccdcaa8f5c0b756f3a875 (diff) | |
parent | 719b718ce27f52b2da600cc1abf6a41ac54dfa36 (diff) |
Merge tag 'pull-ppc-20221017' of https://gitlab.com/danielhb/qemu into staging
ppc patch queue for 2022-10-18:
This queue contains improvements in the e500 and ppc4xx boards, changes
in the maintainership of the project, a new QMP/HMP command and bug
fixes:
- Cedric is stepping back from qemu-ppc maintainership;
- ppc4xx_sdram: QOMification and clean ups;
- e500: add new types of flash and clean ups;
- QMP/HMP: introduce dumpdtb command;
- spapr_pci, booke doorbell interrupt and xvcmp* bit fixes;
The 'dumpdtb' implementation is also making changes to RISC-V files that
were acked by Alistair Francis and are being included in this queue.
# -----BEGIN PGP SIGNATURE-----
#
# iHUEABYKAB0WIQQX6/+ZI9AYAK8oOBk82cqW3gMxZAUCY02qEgAKCRA82cqW3gMx
# ZIadAQCYY9f+NFrSJBm3z4JjUaP+GmbgEjibjZW05diyKwbqzQEAjE1KXFCcd40D
# 3Brs2Dm4YruaJCwb68vswVQAYteXaQ8=
# =hl94
# -----END PGP SIGNATURE-----
# gpg: Signature made Mon 17 Oct 2022 15:16:34 EDT
# gpg: using EDDSA key 17EBFF9923D01800AF2838193CD9CA96DE033164
# gpg: Good signature from "Daniel Henrique Barboza <danielhb413@gmail.com>" [unknown]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg: There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 17EB FF99 23D0 1800 AF28 3819 3CD9 CA96 DE03 3164
* tag 'pull-ppc-20221017' of https://gitlab.com/danielhb/qemu: (38 commits)
hw/riscv: set machine->fdt in spike_board_init()
hw/riscv: set machine->fdt in sifive_u_machine_init()
hw/ppc: set machine->fdt in spapr machine
hw/ppc: set machine->fdt in pnv_reset()
hw/ppc: set machine->fdt in pegasos2_machine_reset()
hw/ppc: set machine->fdt in xilinx_load_device_tree()
hw/ppc: set machine->fdt in sam460ex_load_device_tree()
hw/ppc: set machine->fdt in bamboo_load_device_tree()
hw/nios2: set machine->fdt in nios2_load_dtb()
qmp/hmp, device_tree.c: introduce dumpdtb
hw/ppc/spapr_pci.c: Use device_cold_reset() rather than device_legacy_reset()
target/ppc: Fix xvcmp* clearing FI bit
hw/ppc/e500: Remove if statement which is now always true
hw/ppc/mpc8544ds: Add platform bus
hw/ppc/mpc8544ds: Rename wrongly named method
hw/ppc/e500: Reduce usage of sysbus API
docs/system/ppc/ppce500: Add heading for networking chapter
hw/gpio/meson: Introduce dedicated config switch for hw/gpio/mpc8xxx
hw/ppc/meson: Allow e500 boards to be enabled separately
ppc440_uc.c: Remove unneeded parenthesis
...
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Diffstat (limited to 'hw')
-rw-r--r-- | hw/gpio/Kconfig | 3 | ||||
-rw-r--r-- | hw/gpio/meson.build | 2 | ||||
-rw-r--r-- | hw/nios2/boot.c | 8 | ||||
-rw-r--r-- | hw/nios2/meson.build | 2 | ||||
-rw-r--r-- | hw/ppc/Kconfig | 9 | ||||
-rw-r--r-- | hw/ppc/e500.c | 30 | ||||
-rw-r--r-- | hw/ppc/e500.h | 1 | ||||
-rw-r--r-- | hw/ppc/e500plat.c | 1 | ||||
-rw-r--r-- | hw/ppc/meson.build | 6 | ||||
-rw-r--r-- | hw/ppc/mpc8544ds.c | 9 | ||||
-rw-r--r-- | hw/ppc/pegasos2.c | 4 | ||||
-rw-r--r-- | hw/ppc/pnv.c | 8 | ||||
-rw-r--r-- | hw/ppc/ppc405.h | 8 | ||||
-rw-r--r-- | hw/ppc/ppc405_boards.c | 13 | ||||
-rw-r--r-- | hw/ppc/ppc405_uc.c | 33 | ||||
-rw-r--r-- | hw/ppc/ppc440.h | 4 | ||||
-rw-r--r-- | hw/ppc/ppc440_bamboo.c | 50 | ||||
-rw-r--r-- | hw/ppc/ppc440_uc.c | 257 | ||||
-rw-r--r-- | hw/ppc/ppc4xx_devs.c | 241 | ||||
-rw-r--r-- | hw/ppc/sam460ex.c | 65 | ||||
-rw-r--r-- | hw/ppc/spapr.c | 3 | ||||
-rw-r--r-- | hw/ppc/spapr_hcall.c | 8 | ||||
-rw-r--r-- | hw/ppc/spapr_pci.c | 2 | ||||
-rw-r--r-- | hw/ppc/virtex_ml507.c | 25 | ||||
-rw-r--r-- | hw/riscv/sifive_u.c | 3 | ||||
-rw-r--r-- | hw/riscv/spike.c | 6 |
26 files changed, 446 insertions, 355 deletions
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 <libfdt.h> + #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); - - 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)); - } + 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); - 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 <libfdt.h> + #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) +{ + 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->bcr[i] & 1) { + 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; - - 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); + 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 + }; + + 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); + + 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); - 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); + 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; - - 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 */ + Ppc4xxSdramDdrState *sdram = PPC4xx_SDRAM_DDR(dev); + + 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) -{ - ppc4xx_sdram_t *sdram; - - 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); +static void ppc4xx_sdram_ddr_realize(DeviceState *dev, Error **errp) +{ + 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 + }; + + 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 <libfdt.h> + #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 <libfdt.h> + 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, |