aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Hajnoczi <stefanha@redhat.com>2022-10-18 11:13:57 -0400
committerStefan Hajnoczi <stefanha@redhat.com>2022-10-18 11:13:58 -0400
commit2c65091fd9d387b8dca8115dbdd9c3c61f658a9e (patch)
tree17268b797cd7833332b5b1504c0392daacbd1d39
parent8823ef1336d6c4af1a6ccdcaa8f5c0b756f3a875 (diff)
parent719b718ce27f52b2da600cc1abf6a41ac54dfa36 (diff)
downloadqemu-2c65091fd9d387b8dca8115dbdd9c3c61f658a9e.zip
qemu-2c65091fd9d387b8dca8115dbdd9c3c61f658a9e.tar.gz
qemu-2c65091fd9d387b8dca8115dbdd9c3c61f658a9e.tar.bz2
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>
-rw-r--r--MAINTAINERS10
-rw-r--r--configs/devices/ppc-softmmu/default.mak3
-rw-r--r--docs/system/ppc/ppce500.rst3
-rw-r--r--hmp-commands.hx15
-rw-r--r--hw/gpio/Kconfig3
-rw-r--r--hw/gpio/meson.build2
-rw-r--r--hw/nios2/boot.c8
-rw-r--r--hw/nios2/meson.build2
-rw-r--r--hw/ppc/Kconfig9
-rw-r--r--hw/ppc/e500.c30
-rw-r--r--hw/ppc/e500.h1
-rw-r--r--hw/ppc/e500plat.c1
-rw-r--r--hw/ppc/meson.build6
-rw-r--r--hw/ppc/mpc8544ds.c9
-rw-r--r--hw/ppc/pegasos2.c4
-rw-r--r--hw/ppc/pnv.c8
-rw-r--r--hw/ppc/ppc405.h8
-rw-r--r--hw/ppc/ppc405_boards.c13
-rw-r--r--hw/ppc/ppc405_uc.c33
-rw-r--r--hw/ppc/ppc440.h4
-rw-r--r--hw/ppc/ppc440_bamboo.c50
-rw-r--r--hw/ppc/ppc440_uc.c257
-rw-r--r--hw/ppc/ppc4xx_devs.c241
-rw-r--r--hw/ppc/sam460ex.c65
-rw-r--r--hw/ppc/spapr.c3
-rw-r--r--hw/ppc/spapr_hcall.c8
-rw-r--r--hw/ppc/spapr_pci.c2
-rw-r--r--hw/ppc/virtex_ml507.c25
-rw-r--r--hw/riscv/sifive_u.c3
-rw-r--r--hw/riscv/spike.c6
-rw-r--r--include/hw/ppc/ppc4xx.h63
-rw-r--r--include/sysemu/device_tree.h1
-rw-r--r--monitor/misc.c1
-rw-r--r--qapi/machine.json18
-rw-r--r--softmmu/device_tree.c37
-rw-r--r--target/ppc/excp_helper.c6
-rw-r--r--target/ppc/translate/vsx-impl.c.inc1
37 files changed, 589 insertions, 370 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index f169fec..e3d5b7e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -267,8 +267,8 @@ F: hw/openrisc/
F: tests/tcg/openrisc/
PowerPC TCG CPUs
-M: Cédric Le Goater <clg@kaod.org>
M: Daniel Henrique Barboza <danielhb413@gmail.com>
+R: Cédric Le Goater <clg@kaod.org>
R: David Gibson <david@gibson.dropbear.id.au>
R: Greg Kurz <groug@kaod.org>
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 <clg@kaod.org>
M: Daniel Henrique Barboza <danielhb413@gmail.com>
+R: Cédric Le Goater <clg@kaod.org>
R: David Gibson <david@gibson.dropbear.id.au>
R: Greg Kurz <groug@kaod.org>
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 <clg@kaod.org>
M: Daniel Henrique Barboza <danielhb413@gmail.com>
+R: Cédric Le Goater <clg@kaod.org>
R: David Gibson <david@gibson.dropbear.id.au>
R: Greg Kurz <groug@kaod.org>
L: qemu-ppc@nongnu.org
@@ -1387,7 +1387,7 @@ F: tests/avocado/ppc_pseries.py
PowerNV (Non-Virtualized)
M: Cédric Le Goater <clg@kaod.org>
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 <clg@kaod.org>
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 658a454..a887f54 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 9beef39..ba6bcb7 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 8ab8000..12b6d4e 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 f0e7405..d2cf3ac 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 7bd6a57..b726e6d 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 21cbfff..b30a7b1 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 6c58e808..22277bd 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 3a4418a..791fe78 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 32495d0..3e950ea 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 1e5853b..68f754c 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 fc911bb..5bb1c60 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 6280192..32babc9 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 8117750..7dd5219 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 61f4263..ecf682b 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 78e00af..40bb573 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 1e558c7..9a43126 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 083f12b..4092ebc 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 2ca42fd..c973cfb 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 7cef936..7c24db8 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 ea945a1..81d71ad 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 53e981d..5fbf440 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 ce38ae6..12af90f 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 850bb3b..4a22ce3 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 8bbaf4f..f79ac85 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 a8d4a6b..891206e 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 57c8a4f..7b7618d 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 493ea0c..13cace2 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 e4c814a..b139824 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 5ba3454..1e1d752 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,
diff --git a/include/hw/ppc/ppc4xx.h b/include/hw/ppc/ppc4xx.h
index a1781af..10c6dd5 100644
--- a/include/hw/ppc/ppc4xx.h
+++ b/include/hw/ppc/ppc4xx.h
@@ -29,17 +29,18 @@
#include "exec/memory.h"
#include "hw/sysbus.h"
+typedef struct {
+ MemoryRegion ram;
+ MemoryRegion container; /* used for clipping */
+ hwaddr base;
+ hwaddr size;
+ uint32_t bcr;
+} Ppc4xxSdramBank;
+
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[]);
-void ppc4xx_sdram_init (CPUPPCState *env, qemu_irq irq, int nbanks,
- MemoryRegion ram_memories[],
- hwaddr *ram_bases,
- hwaddr *ram_sizes,
- int do_init);
-
#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 ef060a9..e7c5441 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 6436a87..205487e 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 abb2f48..b9228a5 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 6ca3fad..ce74f3d 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 <libfdt.h>
@@ -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 214acf5..43f2480 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 7acdbce..e6e5c45 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); \