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-----

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>
This commit is contained in:
Stefan Hajnoczi 2022-10-18 11:13:57 -04:00
commit 2c65091fd9
37 changed files with 586 additions and 367 deletions

View file

@ -267,8 +267,8 @@ F: hw/openrisc/
F: tests/tcg/openrisc/ F: tests/tcg/openrisc/
PowerPC TCG CPUs PowerPC TCG CPUs
M: Cédric Le Goater <clg@kaod.org>
M: Daniel Henrique Barboza <danielhb413@gmail.com> M: Daniel Henrique Barboza <danielhb413@gmail.com>
R: Cédric Le Goater <clg@kaod.org>
R: David Gibson <david@gibson.dropbear.id.au> R: David Gibson <david@gibson.dropbear.id.au>
R: Greg Kurz <groug@kaod.org> R: Greg Kurz <groug@kaod.org>
L: qemu-ppc@nongnu.org L: qemu-ppc@nongnu.org
@ -392,8 +392,8 @@ F: target/mips/kvm*
F: target/mips/sysemu/ F: target/mips/sysemu/
PPC KVM CPUs PPC KVM CPUs
M: Cédric Le Goater <clg@kaod.org>
M: Daniel Henrique Barboza <danielhb413@gmail.com> M: Daniel Henrique Barboza <danielhb413@gmail.com>
R: Cédric Le Goater <clg@kaod.org>
R: David Gibson <david@gibson.dropbear.id.au> R: David Gibson <david@gibson.dropbear.id.au>
R: Greg Kurz <groug@kaod.org> R: Greg Kurz <groug@kaod.org>
S: Maintained S: Maintained
@ -1365,8 +1365,8 @@ F: include/hw/rtc/m48t59.h
F: tests/avocado/ppc_prep_40p.py F: tests/avocado/ppc_prep_40p.py
sPAPR (pseries) sPAPR (pseries)
M: Cédric Le Goater <clg@kaod.org>
M: Daniel Henrique Barboza <danielhb413@gmail.com> M: Daniel Henrique Barboza <danielhb413@gmail.com>
R: Cédric Le Goater <clg@kaod.org>
R: David Gibson <david@gibson.dropbear.id.au> R: David Gibson <david@gibson.dropbear.id.au>
R: Greg Kurz <groug@kaod.org> R: Greg Kurz <groug@kaod.org>
L: qemu-ppc@nongnu.org L: qemu-ppc@nongnu.org
@ -1387,7 +1387,7 @@ F: tests/avocado/ppc_pseries.py
PowerNV (Non-Virtualized) PowerNV (Non-Virtualized)
M: Cédric Le Goater <clg@kaod.org> M: Cédric Le Goater <clg@kaod.org>
L: qemu-ppc@nongnu.org L: qemu-ppc@nongnu.org
S: Maintained S: Odd Fixes
F: docs/system/ppc/powernv.rst F: docs/system/ppc/powernv.rst
F: hw/ppc/pnv* F: hw/ppc/pnv*
F: hw/intc/pnv* F: hw/intc/pnv*
@ -2333,7 +2333,7 @@ T: git https://github.com/philmd/qemu.git fw_cfg-next
XIVE XIVE
M: Cédric Le Goater <clg@kaod.org> M: Cédric Le Goater <clg@kaod.org>
L: qemu-ppc@nongnu.org L: qemu-ppc@nongnu.org
S: Supported S: Odd Fixes
F: hw/*/*xive* F: hw/*/*xive*
F: include/hw/*/*xive* F: include/hw/*/*xive*
F: docs/*/*xive* F: docs/*/*xive*

View file

@ -1,7 +1,8 @@
# Default configuration for ppc-softmmu # Default configuration for ppc-softmmu
# For embedded PPCs: # For embedded PPCs:
CONFIG_E500=y CONFIG_E500PLAT=y
CONFIG_MPC8544DS=y
CONFIG_PPC405=y CONFIG_PPC405=y
CONFIG_PPC440=y CONFIG_PPC440=y
CONFIG_VIRTEX=y CONFIG_VIRTEX=y

View file

@ -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 these SoCs are e500v2 based MPC85xx series, hence you cannot test anything
built for P4080 (e500mc), P5020 (e5500) and T2080 (e6500). built for P4080 (e500mc), P5020 (e5500) and T2080 (e6500).
Networking
----------
By default a VirtIO standard PCI networking device is connected as an ethernet 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: interface at PCI address 0.1.0, but we can switch that to an e1000 NIC by:

View file

@ -1800,3 +1800,18 @@ ERST
.sub_table = hmp_info_cmds, .sub_table = hmp_info_cmds,
.flags = "p", .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

View file

@ -8,6 +8,9 @@ config PL061
config GPIO_KEY config GPIO_KEY
bool bool
config GPIO_MPC8XXX
bool
config GPIO_PWR config GPIO_PWR
bool bool

View file

@ -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_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_GPIO_PWR', if_true: files('gpio_pwr.c'))
softmmu_ss.add(when: 'CONFIG_MAX7310', if_true: files('max7310.c')) softmmu_ss.add(when: 'CONFIG_MAX7310', if_true: files('max7310.c'))
softmmu_ss.add(when: 'CONFIG_PL061', if_true: files('pl061.c')) softmmu_ss.add(when: 'CONFIG_PL061', if_true: files('pl061.c'))

View file

@ -43,6 +43,8 @@
#include "boot.h" #include "boot.h"
#include <libfdt.h>
#define NIOS2_MAGIC 0x534f494e #define NIOS2_MAGIC 0x534f494e
static struct nios2_boot_info { 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, static int nios2_load_dtb(struct nios2_boot_info bi, const uint32_t ramsize,
const char *kernel_cmdline, const char *dtb_filename) const char *kernel_cmdline, const char *dtb_filename)
{ {
MachineState *machine = MACHINE(qdev_get_machine());
int fdt_size; int fdt_size;
void *fdt = NULL; void *fdt = NULL;
int r; 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); 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; return fdt_size;
} }

View file

@ -1,5 +1,5 @@
nios2_ss = ss.source_set() 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_10M50', if_true: files('10m50_devboard.c'))
nios2_ss.add(when: 'CONFIG_NIOS2_GENERIC_NOMMU', if_true: files('generic_nommu.c')) nios2_ss.add(when: 'CONFIG_NIOS2_GENERIC_NOMMU', if_true: files('generic_nommu.c'))

View file

@ -124,6 +124,7 @@ config E500
imply AT24C imply AT24C
imply VIRTIO_PCI imply VIRTIO_PCI
select ETSEC select ETSEC
select GPIO_MPC8XXX
select OPENPIC select OPENPIC
select PLATFORM_BUS select PLATFORM_BUS
select PPCE500_PCI select PPCE500_PCI
@ -132,6 +133,14 @@ config E500
select FDT_PPC select FDT_PPC
select DS1338 select DS1338
config E500PLAT
bool
select E500
config MPC8544DS
bool
select E500
config VIRTEX config VIRTEX
bool bool
select PPC4XX select PPC4XX

View file

@ -1007,7 +1007,6 @@ void ppce500_init(MachineState *machine)
} }
/* Platform Bus Device */ /* Platform Bus Device */
if (pmc->has_platform_bus) {
dev = qdev_new(TYPE_PLATFORM_BUS_DEVICE); dev = qdev_new(TYPE_PLATFORM_BUS_DEVICE);
dev->id = g_strdup(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, "num_irqs", pmc->platform_bus_num_irqs);
@ -1023,8 +1022,7 @@ void ppce500_init(MachineState *machine)
memory_region_add_subregion(address_space_mem, memory_region_add_subregion(address_space_mem,
pmc->platform_bus_base, pmc->platform_bus_base,
sysbus_mmio_get_region(s, 0)); &pms->pbus_dev->mmio);
}
/* /*
* Smart firmware defaults ahead! * Smart firmware defaults ahead!

View file

@ -27,7 +27,6 @@ struct PPCE500MachineClass {
int mpic_version; int mpic_version;
bool has_mpc8xxx_gpio; bool has_mpc8xxx_gpio;
bool has_platform_bus;
hwaddr platform_bus_base; hwaddr platform_bus_base;
hwaddr platform_bus_size; hwaddr platform_bus_size;
int platform_bus_first_irq; int platform_bus_first_irq;

View file

@ -86,7 +86,6 @@ static void e500plat_machine_class_init(ObjectClass *oc, void *data)
pmc->fixup_devtree = e500plat_fixup_devtree; pmc->fixup_devtree = e500plat_fixup_devtree;
pmc->mpic_version = OPENPIC_MODEL_FSL_MPIC_42; pmc->mpic_version = OPENPIC_MODEL_FSL_MPIC_42;
pmc->has_mpc8xxx_gpio = true; pmc->has_mpc8xxx_gpio = true;
pmc->has_platform_bus = true;
pmc->platform_bus_base = 0xf00000000ULL; pmc->platform_bus_base = 0xf00000000ULL;
pmc->platform_bus_size = 128 * MiB; pmc->platform_bus_size = 128 * MiB;
pmc->platform_bus_first_irq = 5; pmc->platform_bus_first_irq = 5;

View file

@ -71,12 +71,10 @@ ppc_ss.add(when: 'CONFIG_MAC_OLDWORLD', if_true: files('mac_oldworld.c'))
# NewWorld PowerMac # NewWorld PowerMac
ppc_ss.add(when: 'CONFIG_MAC_NEWWORLD', if_true: files('mac_newworld.c')) ppc_ss.add(when: 'CONFIG_MAC_NEWWORLD', if_true: files('mac_newworld.c'))
# e500 # 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( ppc_ss.add(when: 'CONFIG_E500', if_true: files(
'e500.c', 'e500.c',
'mpc8544ds.c',
'e500plat.c'
))
ppc_ss.add(when: 'CONFIG_E500', if_true: files(
'mpc8544_guts.c', 'mpc8544_guts.c',
'ppce500_spin.c' 'ppce500_spin.c'
)) ))

View file

@ -14,6 +14,7 @@
#include "sysemu/device_tree.h" #include "sysemu/device_tree.h"
#include "hw/ppc/openpic.h" #include "hw/ppc/openpic.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"
#include "qemu/units.h"
#include "cpu.h" #include "cpu.h"
static void mpc8544ds_fixup_devtree(void *fdt) static void mpc8544ds_fixup_devtree(void *fdt)
@ -36,7 +37,7 @@ static void mpc8544ds_init(MachineState *machine)
ppce500_init(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); MachineClass *mc = MACHINE_CLASS(oc);
PPCE500MachineClass *pmc = PPCE500_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->pci_nr_slots = 2;
pmc->fixup_devtree = mpc8544ds_fixup_devtree; pmc->fixup_devtree = mpc8544ds_fixup_devtree;
pmc->mpic_version = OPENPIC_MODEL_FSL_MPIC_20; 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->ccsrbar_base = 0xE0000000ULL;
pmc->pci_mmio_base = 0xC0000000ULL; pmc->pci_mmio_base = 0xC0000000ULL;
pmc->pci_mmio_bus_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 = { static const TypeInfo mpc8544ds_info = {
.name = TYPE_MPC8544DS_MACHINE, .name = TYPE_MPC8544DS_MACHINE,
.parent = TYPE_PPCE500_MACHINE, .parent = TYPE_PPCE500_MACHINE,
.class_init = e500plat_machine_class_init, .class_init = mpc8544ds_machine_class_init,
}; };
static void mpc8544ds_register_types(void) static void mpc8544ds_register_types(void)

View file

@ -331,6 +331,10 @@ static void pegasos2_machine_reset(MachineState *machine)
vof_build_dt(fdt, pm->vof); vof_build_dt(fdt, pm->vof);
vof_client_open_store(fdt, pm->vof, "/chosen", "stdout", "/failsafe"); 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); pm->cpu->vhyp = PPC_VIRTUAL_HYPERVISOR(machine);
} }

View file

@ -678,7 +678,13 @@ static void pnv_reset(MachineState *machine)
qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt)); qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt));
cpu_physical_memory_write(PNV_FDT_ADDR, 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) static ISABus *pnv_chip_power8_isa_create(PnvChip *chip, Error **errp)

View file

@ -167,13 +167,6 @@ struct Ppc405SoCState {
DeviceState parent_obj; DeviceState parent_obj;
/* Public */ /* Public */
MemoryRegion ram_banks[2];
hwaddr ram_bases[2], ram_sizes[2];
bool do_dram_init;
MemoryRegion *dram_mr;
hwaddr ram_size;
PowerPCCPU cpu; PowerPCCPU cpu;
PPCUIC uic; PPCUIC uic;
Ppc405CpcState cpc; Ppc405CpcState cpc;
@ -187,6 +180,7 @@ struct Ppc405SoCState {
Ppc405PobState pob; Ppc405PobState pob;
Ppc4xxPlbState plb; Ppc4xxPlbState plb;
Ppc4xxMalState mal; Ppc4xxMalState mal;
Ppc4xxSdramDdrState sdram;
}; };
#endif /* PPC405_H */ #endif /* PPC405_H */

View file

@ -271,25 +271,13 @@ static void boot_from_kernel(MachineState *machine, PowerPCCPU *cpu)
static void ppc405_init(MachineState *machine) static void ppc405_init(MachineState *machine)
{ {
Ppc405MachineState *ppc405 = PPC405_MACHINE(machine); Ppc405MachineState *ppc405 = PPC405_MACHINE(machine);
MachineClass *mc = MACHINE_GET_CLASS(machine);
const char *kernel_filename = machine->kernel_filename; const char *kernel_filename = machine->kernel_filename;
MemoryRegion *sysmem = get_system_memory(); 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, object_initialize_child(OBJECT(machine), "soc", &ppc405->soc,
TYPE_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_property_set_link(OBJECT(&ppc405->soc), "dram",
OBJECT(machine->ram), &error_abort); 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, object_property_set_uint(OBJECT(&ppc405->soc), "sys-clk", 33333333,
&error_abort); &error_abort);
qdev_realize(DEVICE(&ppc405->soc), NULL, &error_fatal); qdev_realize(DEVICE(&ppc405->soc), NULL, &error_fatal);
@ -349,6 +337,7 @@ static void ppc405_init(MachineState *machine)
/* Load ELF kernel and rootfs.cpio */ /* Load ELF kernel and rootfs.cpio */
} else if (kernel_filename && !machine->firmware) { } else if (kernel_filename && !machine->firmware) {
ppc4xx_sdram_ddr_enable(&ppc405->soc.sdram);
boot_from_kernel(machine, &ppc405->soc.cpu); boot_from_kernel(machine, &ppc405->soc.cpu);
} }
} }

View file

@ -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, "plb", &s->plb, TYPE_PPC4xx_PLB);
object_initialize_child(obj, "mal", &s->mal, TYPE_PPC4xx_MAL); 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) 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)); qdev_get_gpio_in(DEVICE(&s->cpu), PPC40x_INPUT_CINT));
/* SDRAM controller */ /* SDRAM controller */
/*
* 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 */ /* XXX 405EP has no ECC interrupt */
s->ram_bases[0] = 0; sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdram), 0,
s->ram_sizes[0] = s->ram_size; qdev_get_gpio_in(DEVICE(&s->uic), 17));
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);
/* External bus controller */ /* External bus controller */
if (!ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(&s->ebc), &s->cpu, errp)) { 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 */ /* 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) static void ppc405_soc_class_init(ObjectClass *oc, void *data)
{ {
DeviceClass *dc = DEVICE_CLASS(oc); DeviceClass *dc = DEVICE_CLASS(oc);
@ -1172,7 +1168,6 @@ static void ppc405_soc_class_init(ObjectClass *oc, void *data)
dc->realize = ppc405_soc_realize; dc->realize = ppc405_soc_realize;
/* Reason: only works as part of a ppc405 board/machine */ /* Reason: only works as part of a ppc405 board/machine */
dc->user_creatable = false; dc->user_creatable = false;
device_class_set_props(dc, ppc405_soc_properties);
} }
static const TypeInfo ppc405_types[] = { static const TypeInfo ppc405_types[] = {

View file

@ -16,10 +16,6 @@
void ppc4xx_l2sram_init(CPUPPCState *env); void ppc4xx_l2sram_init(CPUPPCState *env);
void ppc4xx_cpr_init(CPUPPCState *env); void ppc4xx_cpr_init(CPUPPCState *env);
void ppc4xx_sdr_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_ahb_init(CPUPPCState *env);
void ppc4xx_dma_init(CPUPPCState *env, int dcr_base); void ppc4xx_dma_init(CPUPPCState *env, int dcr_base);
void ppc460ex_pcie_init(CPUPPCState *env); void ppc460ex_pcie_init(CPUPPCState *env);

View file

@ -34,6 +34,8 @@
#include "hw/qdev-properties.h" #include "hw/qdev-properties.h"
#include "qapi/error.h" #include "qapi/error.h"
#include <libfdt.h>
#define BINARY_DEVICE_TREE_FILE "bamboo.dtb" #define BINARY_DEVICE_TREE_FILE "bamboo.dtb"
/* from u-boot */ /* from u-boot */
@ -48,22 +50,15 @@
#define PPC440EP_PCI_IO 0xe8000000 #define PPC440EP_PCI_IO 0xe8000000
#define PPC440EP_PCI_IOLEN 0x00010000 #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 hwaddr entry;
static int bamboo_load_device_tree(hwaddr addr, static int bamboo_load_device_tree(MachineState *machine,
uint32_t ramsize, hwaddr addr,
hwaddr initrd_base, hwaddr initrd_base,
hwaddr initrd_size, hwaddr initrd_size)
const char *kernel_cmdline)
{ {
int ret = -1; 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; char *filename;
int fdt_size; int fdt_size;
void *fdt; void *fdt;
@ -98,7 +93,7 @@ static int bamboo_load_device_tree(hwaddr addr,
fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n"); fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
} }
ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
kernel_cmdline); machine->kernel_cmdline);
if (ret < 0) { if (ret < 0) {
fprintf(stderr, "couldn't set /chosen/bootargs\n"); fprintf(stderr, "couldn't set /chosen/bootargs\n");
} }
@ -119,7 +114,10 @@ static int bamboo_load_device_tree(hwaddr addr,
tb_freq); tb_freq);
rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr); 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; return 0;
} }
@ -163,14 +161,10 @@ static void main_cpu_reset(void *opaque)
static void bamboo_init(MachineState *machine) static void bamboo_init(MachineState *machine)
{ {
const char *kernel_filename = machine->kernel_filename; const char *kernel_filename = machine->kernel_filename;
const char *kernel_cmdline = machine->kernel_cmdline;
const char *initrd_filename = machine->initrd_filename; const char *initrd_filename = machine->initrd_filename;
unsigned int pci_irq_nrs[4] = { 28, 27, 26, 25 }; unsigned int pci_irq_nrs[4] = { 28, 27, 26, 25 };
MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *address_space_mem = get_system_memory();
MemoryRegion *isa = g_new(MemoryRegion, 1); 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; PCIBus *pcibus;
PowerPCCPU *cpu; PowerPCCPU *cpu;
CPUPPCState *env; CPUPPCState *env;
@ -205,15 +199,15 @@ static void bamboo_init(MachineState *machine)
qdev_get_gpio_in(DEVICE(cpu), PPC40x_INPUT_CINT)); qdev_get_gpio_in(DEVICE(cpu), PPC40x_INPUT_CINT));
/* SDRAM controller */ /* SDRAM controller */
memset(ram_bases, 0, sizeof(ram_bases)); dev = qdev_new(TYPE_PPC4xx_SDRAM_DDR);
memset(ram_sizes, 0, sizeof(ram_sizes)); object_property_set_link(OBJECT(dev), "dram", OBJECT(machine->ram),
ppc4xx_sdram_banks(machine->ram, PPC440EP_SDRAM_NR_BANKS, ram_memories, &error_abort);
ram_bases, ram_sizes, ppc440ep_sdram_bank_sizes); 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. */ /* XXX 440EP's ECC interrupts are on UIC1, but we've only created UIC0. */
ppc4xx_sdram_init(env, sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(uicdev, 14));
qdev_get_gpio_in(uicdev, 14), /* Enable SDRAM memory regions, this should be done by the firmware */
PPC440EP_SDRAM_NR_BANKS, ram_memories, ppc4xx_sdram_ddr_enable(PPC4xx_SDRAM_DDR(dev));
ram_bases, ram_sizes, 1);
/* PCI */ /* PCI */
dev = sysbus_create_varargs(TYPE_PPC4xx_PCI_HOST_BRIDGE, 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 we're loading a kernel directly, we must load the device tree too. */
if (kernel_filename) { if (kernel_filename) {
if (bamboo_load_device_tree(FDT_ADDR, machine->ram_size, RAMDISK_ADDR, if (bamboo_load_device_tree(machine, FDT_ADDR,
initrd_size, kernel_cmdline) < 0) { RAMDISK_ADDR, initrd_size) < 0) {
error_report("couldn't load device tree"); error_report("couldn't load device tree");
exit(1); exit(1);
} }

View file

@ -16,13 +16,15 @@
#include "qemu/module.h" #include "qemu/module.h"
#include "hw/irq.h" #include "hw/irq.h"
#include "exec/memory.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/qdev-properties.h"
#include "hw/pci/pci.h" #include "hw/pci/pci.h"
#include "sysemu/block-backend.h" #include "sysemu/block-backend.h"
#include "sysemu/reset.h" #include "sysemu/reset.h"
#include "ppc440.h" #include "ppc440.h"
#include "qom/object.h" #include "qom/object.h"
#include "trace.h"
/*****************************************************************************/ /*****************************************************************************/
/* L2 Cache as SRAM */ /* L2 Cache as SRAM */
@ -378,10 +380,6 @@ enum {
PESDR1_RSTSTA = 0x365, 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) static uint32_t dcr_read_sdr(void *opaque, int dcrn)
{ {
ppc4xx_sdr_t *sdr = opaque; ppc4xx_sdr_t *sdr = opaque;
@ -482,16 +480,6 @@ void ppc4xx_sdr_init(CPUPPCState *env)
/*****************************************************************************/ /*****************************************************************************/
/* SDRAM controller */ /* 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 { enum {
SDRAM0_CFGADDR = 0x10, SDRAM0_CFGADDR = 0x10,
SDRAM0_CFGDATA, SDRAM0_CFGDATA,
@ -506,39 +494,39 @@ enum {
SDRAM_PLBADDUHB = 0x50, 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; uint32_t bcr;
switch (ram_size) { switch (ram_size) {
case (8 * MiB): case 8 * MiB:
bcr = 0xffc0; bcr = 0xffc0;
break; break;
case (16 * MiB): case 16 * MiB:
bcr = 0xff80; bcr = 0xff80;
break; break;
case (32 * MiB): case 32 * MiB:
bcr = 0xff00; bcr = 0xff00;
break; break;
case (64 * MiB): case 64 * MiB:
bcr = 0xfe00; bcr = 0xfe00;
break; break;
case (128 * MiB): case 128 * MiB:
bcr = 0xfc00; bcr = 0xfc00;
break; break;
case (256 * MiB): case 256 * MiB:
bcr = 0xf800; bcr = 0xf800;
break; break;
case (512 * MiB): case 512 * MiB:
bcr = 0xf000; bcr = 0xf000;
break; break;
case (1 * GiB): case 1 * GiB:
bcr = 0xe000; bcr = 0xe000;
break; break;
case (2 * GiB): case 2 * GiB:
bcr = 0xc000; bcr = 0xc000;
break; break;
case (4 * GiB): case 4 * GiB:
bcr = 0x8000; bcr = 0x8000;
break; break;
default: default:
@ -551,12 +539,12 @@ static uint32_t sdram_bcr(hwaddr ram_base, hwaddr ram_size)
return bcr; return bcr;
} }
static inline hwaddr sdram_base(uint32_t bcr) static inline hwaddr sdram_ddr2_base(uint32_t bcr)
{ {
return (bcr & 0xffe00000) << 2; return (bcr & 0xffe00000) << 2;
} }
static uint64_t sdram_size(uint32_t bcr) static uint64_t sdram_ddr2_size(uint32_t bcr)
{ {
uint64_t size; uint64_t size;
int sh; int sh;
@ -567,46 +555,66 @@ static uint64_t sdram_size(uint32_t bcr)
return size; return size;
} }
static void sdram_set_bcr(ppc440_sdram_t *sdram, int i, 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) uint32_t bcr, int enabled)
{ {
if (sdram->bcr[i] & 1) { if (sdram->bank[i].bcr & 1) {
/* First unmap RAM if enabled */ /* First unmap RAM if enabled */
memory_region_del_subregion(get_system_memory(), trace_ppc4xx_sdram_unmap(sdram_ddr2_base(sdram->bank[i].bcr),
&sdram->containers[i]); sdram_ddr2_size(sdram->bank[i].bcr));
memory_region_del_subregion(&sdram->containers[i], sdram_bank_unmap(&sdram->bank[i]);
&sdram->ram_memories[i]);
object_unparent(OBJECT(&sdram->containers[i]));
} }
sdram->bcr[i] = bcr & 0xffe0ffc1; sdram->bank[i].bcr = bcr & 0xffe0ffc1;
if (enabled && (bcr & 1)) { if (enabled && (bcr & 1)) {
memory_region_init(&sdram->containers[i], NULL, "sdram-containers", trace_ppc4xx_sdram_map(sdram_ddr2_base(bcr), sdram_ddr2_size(bcr));
sdram_size(bcr)); sdram_bank_map(&sdram->bank[i]);
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]);
} }
} }
static void sdram_map_bcr(ppc440_sdram_t *sdram) static void sdram_ddr2_map_bcr(Ppc4xxSdramDdr2State *sdram)
{ {
int i; int i;
for (i = 0; i < sdram->nbanks; i++) { for (i = 0; i < sdram->nbanks; i++) {
if (sdram->ram_sizes[i] != 0) { if (sdram->bank[i].size) {
sdram_set_bcr(sdram, i, sdram_bcr(sdram->ram_bases[i], sdram_ddr2_set_bcr(sdram, i,
sdram->ram_sizes[i]), 1); sdram_ddr2_bcr(sdram->bank[i].base,
sdram->bank[i].size), 1);
} else { } 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; uint32_t ret = 0;
switch (dcrn) { switch (dcrn) {
@ -614,9 +622,9 @@ static uint32_t dcr_read_sdram(void *opaque, int dcrn)
case SDRAM_R1BAS: case SDRAM_R1BAS:
case SDRAM_R2BAS: case SDRAM_R2BAS:
case SDRAM_R3BAS: case SDRAM_R3BAS:
if (sdram->ram_sizes[dcrn - SDRAM_R0BAS]) { if (sdram->bank[dcrn - SDRAM_R0BAS].size) {
ret = sdram_bcr(sdram->ram_bases[dcrn - SDRAM_R0BAS], ret = sdram_ddr2_bcr(sdram->bank[dcrn - SDRAM_R0BAS].base,
sdram->ram_sizes[dcrn - SDRAM_R0BAS]); sdram->bank[dcrn - SDRAM_R0BAS].size);
} }
break; break;
case SDRAM_CONF1HB: case SDRAM_CONF1HB:
@ -635,7 +643,7 @@ static uint32_t dcr_read_sdram(void *opaque, int dcrn)
ret = 0x80000000; ret = 0x80000000;
break; break;
case 0x21: /* SDRAM_MCOPT2 */ case 0x21: /* SDRAM_MCOPT2 */
ret = 0x08000000; ret = sdram->mcopt2;
break; break;
case 0x40: /* SDRAM_MB0CF */ case 0x40: /* SDRAM_MB0CF */
ret = 0x00008001; ret = 0x00008001;
@ -657,9 +665,11 @@ static uint32_t dcr_read_sdram(void *opaque, int dcrn)
return ret; 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) { switch (dcrn) {
case SDRAM_R0BAS: case SDRAM_R0BAS:
@ -679,6 +689,21 @@ static void dcr_write_sdram(void *opaque, int dcrn, uint32_t val)
switch (sdram->addr) { switch (sdram->addr) {
case 0x00: /* B0CR */ case 0x00: /* B0CR */
break; 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: default:
break; 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->addr = 0;
sdram->mcopt2 = 0;
} }
void ppc440_sdram_init(CPUPPCState *env, int nbanks, static void ppc4xx_sdram_ddr2_realize(DeviceState *dev, Error **errp)
MemoryRegion *ram_memories,
hwaddr *ram_bases, hwaddr *ram_sizes,
int do_init)
{ {
ppc440_sdram_t *sdram; Ppc4xxSdramDdr2State *s = PPC4xx_SDRAM_DDR2(dev);
Ppc4xxDcrDeviceState *dcr = PPC4xx_DCR_DEVICE(dev);
/*
* SoC also has 4 GiB but that causes problem with 32 bit
* builds (4*GiB overflows the 32 bit ram_addr_t).
*/
const ram_addr_t valid_bank_sizes[] = {
2 * GiB, 1 * GiB, 512 * MiB, 256 * MiB, 128 * MiB,
64 * MiB, 32 * MiB, 16 * MiB, 8 * MiB, 0
};
sdram = g_malloc0(sizeof(*sdram)); if (s->nbanks < 1 || s->nbanks > 4) {
sdram->nbanks = nbanks; error_setg(errp, "Invalid number of RAM banks");
sdram->ram_memories = ram_memories; return;
memcpy(sdram->ram_bases, ram_bases, nbanks * sizeof(hwaddr)); }
memcpy(sdram->ram_sizes, ram_sizes, nbanks * sizeof(hwaddr)); if (!s->dram_mr) {
qemu_register_reset(&sdram_reset, sdram); error_setg(errp, "Missing dram memory region");
ppc_dcr_register(env, SDRAM0_CFGADDR, return;
sdram, &dcr_read_sdram, &dcr_write_sdram); }
ppc_dcr_register(env, SDRAM0_CFGDATA, ppc4xx_sdram_banks(s->dram_mr, s->nbanks, s->bank, valid_bank_sizes);
sdram, &dcr_read_sdram, &dcr_write_sdram);
if (do_init) { ppc4xx_dcr_register(dcr, SDRAM0_CFGADDR,
sdram_map_bcr(sdram); 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);
} }
ppc_dcr_register(env, SDRAM_R0BAS, static Property ppc4xx_sdram_ddr2_props[] = {
sdram, &dcr_read_sdram, &dcr_write_sdram); DEFINE_PROP_LINK("dram", Ppc4xxSdramDdr2State, dram_mr, TYPE_MEMORY_REGION,
ppc_dcr_register(env, SDRAM_R1BAS, MemoryRegion *),
sdram, &dcr_read_sdram, &dcr_write_sdram); DEFINE_PROP_UINT32("nbanks", Ppc4xxSdramDdr2State, nbanks, 4),
ppc_dcr_register(env, SDRAM_R2BAS, DEFINE_PROP_END_OF_LIST(),
sdram, &dcr_read_sdram, &dcr_write_sdram); };
ppc_dcr_register(env, SDRAM_R3BAS,
sdram, &dcr_read_sdram, &dcr_write_sdram); static void ppc4xx_sdram_ddr2_class_init(ObjectClass *oc, void *data)
ppc_dcr_register(env, SDRAM_CONF1HB, {
sdram, &dcr_read_sdram, &dcr_write_sdram); DeviceClass *dc = DEVICE_CLASS(oc);
ppc_dcr_register(env, SDRAM_PLBADDULL,
sdram, &dcr_read_sdram, &dcr_write_sdram); dc->realize = ppc4xx_sdram_ddr2_realize;
ppc_dcr_register(env, SDRAM_CONF1LL, dc->reset = ppc4xx_sdram_ddr2_reset;
sdram, &dcr_read_sdram, &dcr_write_sdram); /* Reason: only works as function of a ppc4xx SoC */
ppc_dcr_register(env, SDRAM_CONFPATHB, dc->user_creatable = false;
sdram, &dcr_read_sdram, &dcr_write_sdram); device_class_set_props(dc, ppc4xx_sdram_ddr2_props);
ppc_dcr_register(env, SDRAM_PLBADDUHB,
sdram, &dcr_read_sdram, &dcr_write_sdram);
} }
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 */ /* PLB to AHB bridge */
enum { enum {

View file

@ -38,28 +38,6 @@
/*****************************************************************************/ /*****************************************************************************/
/* SDRAM controller */ /* 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 { enum {
SDRAM0_CFGADDR = 0x010, SDRAM0_CFGADDR = 0x010,
SDRAM0_CFGDATA = 0x011, SDRAM0_CFGDATA = 0x011,
@ -70,37 +48,37 @@ enum {
* there are type inconsistencies, mixing hwaddr, target_ulong * there are type inconsistencies, mixing hwaddr, target_ulong
* and uint32_t * 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; uint32_t bcr;
switch (ram_size) { switch (ram_size) {
case 4 * MiB: case 4 * MiB:
bcr = 0x00000000; bcr = 0;
break; break;
case 8 * MiB: case 8 * MiB:
bcr = 0x00020000; bcr = 0x20000;
break; break;
case 16 * MiB: case 16 * MiB:
bcr = 0x00040000; bcr = 0x40000;
break; break;
case 32 * MiB: case 32 * MiB:
bcr = 0x00060000; bcr = 0x60000;
break; break;
case 64 * MiB: case 64 * MiB:
bcr = 0x00080000; bcr = 0x80000;
break; break;
case 128 * MiB: case 128 * MiB:
bcr = 0x000A0000; bcr = 0xA0000;
break; break;
case 256 * MiB: case 256 * MiB:
bcr = 0x000C0000; bcr = 0xC0000;
break; break;
default: default:
qemu_log_mask(LOG_GUEST_ERROR, qemu_log_mask(LOG_GUEST_ERROR,
"%s: invalid RAM size 0x%" HWADDR_PRIx "\n", __func__, "%s: invalid RAM size 0x%" HWADDR_PRIx "\n", __func__,
ram_size); ram_size);
return 0x00000000; return 0;
} }
bcr |= ram_base & 0xFF800000; bcr |= ram_base & 0xFF800000;
bcr |= 1; bcr |= 1;
@ -108,12 +86,12 @@ static uint32_t sdram_bcr(hwaddr ram_base, hwaddr ram_size)
return bcr; return bcr;
} }
static inline hwaddr sdram_base(uint32_t bcr) static inline hwaddr sdram_ddr_base(uint32_t bcr)
{ {
return bcr & 0xFF800000; return bcr & 0xFF800000;
} }
static target_ulong sdram_size(uint32_t bcr) static target_ulong sdram_ddr_size(uint32_t bcr)
{ {
target_ulong size; target_ulong size;
int sh; int sh;
@ -128,64 +106,63 @@ static target_ulong sdram_size(uint32_t bcr)
return size; return size;
} }
static void sdram_set_bcr(ppc4xx_sdram_t *sdram, int i, static void sdram_ddr_set_bcr(Ppc4xxSdramDdrState *sdram, int i,
uint32_t bcr, int enabled) uint32_t bcr, int enabled)
{ {
if (sdram->bcr[i] & 0x00000001) { if (sdram->bank[i].bcr & 1) {
/* Unmap RAM */ /* Unmap RAM */
trace_ppc4xx_sdram_unmap(sdram_base(sdram->bcr[i]), trace_ppc4xx_sdram_unmap(sdram_ddr_base(sdram->bank[i].bcr),
sdram_size(sdram->bcr[i])); sdram_ddr_size(sdram->bank[i].bcr));
memory_region_del_subregion(get_system_memory(), memory_region_del_subregion(get_system_memory(),
&sdram->containers[i]); &sdram->bank[i].container);
memory_region_del_subregion(&sdram->containers[i], memory_region_del_subregion(&sdram->bank[i].container,
&sdram->ram_memories[i]); &sdram->bank[i].ram);
object_unparent(OBJECT(&sdram->containers[i])); object_unparent(OBJECT(&sdram->bank[i].container));
} }
sdram->bcr[i] = bcr & 0xFFDEE001; sdram->bank[i].bcr = bcr & 0xFFDEE001;
if (enabled && (bcr & 0x00000001)) { if (enabled && (bcr & 1)) {
trace_ppc4xx_sdram_map(sdram_base(bcr), sdram_size(bcr)); trace_ppc4xx_sdram_map(sdram_ddr_base(bcr), sdram_ddr_size(bcr));
memory_region_init(&sdram->containers[i], NULL, "sdram-containers", memory_region_init(&sdram->bank[i].container, NULL, "sdram-container",
sdram_size(bcr)); sdram_ddr_size(bcr));
memory_region_add_subregion(&sdram->containers[i], 0, memory_region_add_subregion(&sdram->bank[i].container, 0,
&sdram->ram_memories[i]); &sdram->bank[i].ram);
memory_region_add_subregion(get_system_memory(), memory_region_add_subregion(get_system_memory(),
sdram_base(bcr), sdram_ddr_base(bcr),
&sdram->containers[i]); &sdram->bank[i].container);
} }
} }
static void sdram_map_bcr(ppc4xx_sdram_t *sdram) static void sdram_ddr_map_bcr(Ppc4xxSdramDdrState *sdram)
{ {
int i; int i;
for (i = 0; i < sdram->nbanks; i++) { for (i = 0; i < sdram->nbanks; i++) {
if (sdram->ram_sizes[i] != 0) { if (sdram->bank[i].size != 0) {
sdram_set_bcr(sdram, i, sdram_bcr(sdram->ram_bases[i], sdram_ddr_set_bcr(sdram, i, sdram_ddr_bcr(sdram->bank[i].base,
sdram->ram_sizes[i]), 1); sdram->bank[i].size), 1);
} else { } 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; int i;
for (i = 0; i < sdram->nbanks; i++) { for (i = 0; i < sdram->nbanks; i++) {
trace_ppc4xx_sdram_unmap(sdram_base(sdram->bcr[i]), trace_ppc4xx_sdram_unmap(sdram_ddr_base(sdram->bank[i].bcr),
sdram_size(sdram->bcr[i])); sdram_ddr_size(sdram->bank[i].bcr));
memory_region_del_subregion(get_system_memory(), 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; uint32_t ret;
sdram = opaque;
switch (dcrn) { switch (dcrn) {
case SDRAM0_CFGADDR: case SDRAM0_CFGADDR:
ret = sdram->addr; ret = sdram->addr;
@ -214,16 +191,16 @@ static uint32_t dcr_read_sdram(void *opaque, int dcrn)
ret = sdram->pmit; ret = sdram->pmit;
break; break;
case 0x40: /* SDRAM_B0CR */ case 0x40: /* SDRAM_B0CR */
ret = sdram->bcr[0]; ret = sdram->bank[0].bcr;
break; break;
case 0x44: /* SDRAM_B1CR */ case 0x44: /* SDRAM_B1CR */
ret = sdram->bcr[1]; ret = sdram->bank[1].bcr;
break; break;
case 0x48: /* SDRAM_B2CR */ case 0x48: /* SDRAM_B2CR */
ret = sdram->bcr[2]; ret = sdram->bank[2].bcr;
break; break;
case 0x4C: /* SDRAM_B3CR */ case 0x4C: /* SDRAM_B3CR */
ret = sdram->bcr[3]; ret = sdram->bank[3].bcr;
break; break;
case 0x80: /* SDRAM_TR */ case 0x80: /* SDRAM_TR */
ret = -1; /* ? */ ret = -1; /* ? */
@ -241,18 +218,17 @@ static uint32_t dcr_read_sdram(void *opaque, int dcrn)
break; break;
default: default:
/* Avoid gcc warning */ /* Avoid gcc warning */
ret = 0x00000000; ret = 0;
break; break;
} }
return ret; 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) { switch (dcrn) {
case SDRAM0_CFGADDR: case SDRAM0_CFGADDR:
sdram->addr = val; 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)) { if (!(sdram->cfg & 0x80000000) && (val & 0x80000000)) {
trace_ppc4xx_sdram_enable("enable"); trace_ppc4xx_sdram_enable("enable");
/* validate all RAM mappings */ /* validate all RAM mappings */
sdram_map_bcr(sdram); sdram_ddr_map_bcr(sdram);
sdram->status &= ~0x80000000; sdram->status &= ~0x80000000;
} else if ((sdram->cfg & 0x80000000) && !(val & 0x80000000)) { } else if ((sdram->cfg & 0x80000000) && !(val & 0x80000000)) {
trace_ppc4xx_sdram_enable("disable"); trace_ppc4xx_sdram_enable("disable");
/* invalidate all RAM mappings */ /* invalidate all RAM mappings */
sdram_unmap_bcr(sdram); sdram_ddr_unmap_bcr(sdram);
sdram->status |= 0x80000000; sdram->status |= 0x80000000;
} }
if (!(sdram->cfg & 0x40000000) && (val & 0x40000000)) { 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; sdram->pmit = (val & 0xF8000000) | 0x07C00000;
break; break;
case 0x40: /* SDRAM_B0CR */ case 0x40: /* SDRAM_B0CR */
sdram_set_bcr(sdram, 0, val, sdram->cfg & 0x80000000); sdram_ddr_set_bcr(sdram, 0, val, sdram->cfg & 0x80000000);
break; break;
case 0x44: /* SDRAM_B1CR */ case 0x44: /* SDRAM_B1CR */
sdram_set_bcr(sdram, 1, val, sdram->cfg & 0x80000000); sdram_ddr_set_bcr(sdram, 1, val, sdram->cfg & 0x80000000);
break; break;
case 0x48: /* SDRAM_B2CR */ case 0x48: /* SDRAM_B2CR */
sdram_set_bcr(sdram, 2, val, sdram->cfg & 0x80000000); sdram_ddr_set_bcr(sdram, 2, val, sdram->cfg & 0x80000000);
break; break;
case 0x4C: /* SDRAM_B3CR */ case 0x4C: /* SDRAM_B3CR */
sdram_set_bcr(sdram, 3, val, sdram->cfg & 0x80000000); sdram_ddr_set_bcr(sdram, 3, val, sdram->cfg & 0x80000000);
break; break;
case 0x80: /* SDRAM_TR */ case 0x80: /* SDRAM_TR */
sdram->tr = val & 0x018FC01F; sdram->tr = val & 0x018FC01F;
@ -331,52 +307,73 @@ static void dcr_write_sdram(void *opaque, int dcrn, uint32_t val)
} }
} }
static void sdram_reset(void *opaque) static void ppc4xx_sdram_ddr_reset(DeviceState *dev)
{ {
ppc4xx_sdram_t *sdram; Ppc4xxSdramDdrState *sdram = PPC4xx_SDRAM_DDR(dev);
sdram = opaque; sdram->addr = 0;
sdram->addr = 0x00000000; sdram->bear = 0;
sdram->bear = 0x00000000; sdram->besr0 = 0; /* No error */
sdram->besr0 = 0x00000000; /* No error */ sdram->besr1 = 0; /* No error */
sdram->besr1 = 0x00000000; /* No error */ sdram->cfg = 0;
sdram->cfg = 0x00000000; sdram->ecccfg = 0; /* No ECC */
sdram->ecccfg = 0x00000000; /* No ECC */ sdram->eccesr = 0; /* No error */
sdram->eccesr = 0x00000000; /* No error */
sdram->pmit = 0x07C00000; sdram->pmit = 0x07C00000;
sdram->rtr = 0x05F00000; sdram->rtr = 0x05F00000;
sdram->tr = 0x00854009; sdram->tr = 0x00854009;
/* We pre-initialize RAM banks */ /* We pre-initialize RAM banks */
sdram->status = 0x00000000; sdram->status = 0;
sdram->cfg = 0x00800000; sdram->cfg = 0x00800000;
} }
void ppc4xx_sdram_init(CPUPPCState *env, qemu_irq irq, int nbanks, static void ppc4xx_sdram_ddr_realize(DeviceState *dev, Error **errp)
MemoryRegion *ram_memories,
hwaddr *ram_bases,
hwaddr *ram_sizes,
int do_init)
{ {
ppc4xx_sdram_t *sdram; Ppc4xxSdramDdrState *s = PPC4xx_SDRAM_DDR(dev);
Ppc4xxDcrDeviceState *dcr = PPC4xx_DCR_DEVICE(dev);
const ram_addr_t valid_bank_sizes[] = {
256 * MiB, 128 * MiB, 64 * MiB, 32 * MiB, 16 * MiB, 8 * MiB, 4 * MiB, 0
};
sdram = g_new0(ppc4xx_sdram_t, 1); if (s->nbanks < 1 || s->nbanks > 4) {
sdram->irq = irq; error_setg(errp, "Invalid number of RAM banks");
sdram->nbanks = nbanks; return;
sdram->ram_memories = ram_memories;
memset(sdram->ram_bases, 0, 4 * sizeof(hwaddr));
memcpy(sdram->ram_bases, ram_bases,
nbanks * sizeof(hwaddr));
memset(sdram->ram_sizes, 0, 4 * sizeof(hwaddr));
memcpy(sdram->ram_sizes, ram_sizes,
nbanks * sizeof(hwaddr));
qemu_register_reset(&sdram_reset, sdram);
ppc_dcr_register(env, SDRAM0_CFGADDR,
sdram, &dcr_read_sdram, &dcr_write_sdram);
ppc_dcr_register(env, SDRAM0_CFGDATA,
sdram, &dcr_read_sdram, &dcr_write_sdram);
if (do_init) {
sdram_map_bcr(sdram);
} }
if (!s->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. * sizes varies by SoC.
*/ */
void ppc4xx_sdram_banks(MemoryRegion *ram, int nr_banks, void ppc4xx_sdram_banks(MemoryRegion *ram, int nr_banks,
MemoryRegion ram_memories[], Ppc4xxSdramBank ram_banks[],
hwaddr ram_bases[], hwaddr ram_sizes[],
const ram_addr_t sdram_bank_sizes[]) const ram_addr_t sdram_bank_sizes[])
{ {
ram_addr_t size_left = memory_region_size(ram); 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) { if (bank_size <= size_left) {
char name[32]; char name[32];
ram_bases[i] = base; ram_banks[i].base = base;
ram_sizes[i] = bank_size; ram_banks[i].size = bank_size;
base += bank_size; base += bank_size;
size_left -= bank_size; size_left -= bank_size;
snprintf(name, sizeof(name), "ppc4xx.sdram%d", i); snprintf(name, sizeof(name), "ppc4xx.sdram%d", i);
memory_region_init_alias(&ram_memories[i], NULL, name, ram, memory_region_init_alias(&ram_banks[i].ram, NULL, name, ram,
ram_bases[i], ram_sizes[i]); ram_banks[i].base, ram_banks[i].size);
break; break;
} }
} }
@ -967,6 +963,11 @@ static void ppc4xx_dcr_class_init(ObjectClass *oc, void *data)
static const TypeInfo ppc4xx_types[] = { 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, .name = TYPE_PPC4xx_MAL,
.parent = TYPE_PPC4xx_DCR_DEVICE, .parent = TYPE_PPC4xx_DCR_DEVICE,
.instance_size = sizeof(Ppc4xxMalState), .instance_size = sizeof(Ppc4xxMalState),

View file

@ -73,14 +73,6 @@
#define OPB_FREQ 115000000 #define OPB_FREQ 115000000
#define EBC_FREQ 115000000 #define EBC_FREQ 115000000
#define UART_FREQ 11059200 #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 { struct boot_info {
uint32_t dt_base; uint32_t dt_base;
@ -131,13 +123,12 @@ static int sam460ex_load_uboot(void)
return 0; return 0;
} }
static int sam460ex_load_device_tree(hwaddr addr, static int sam460ex_load_device_tree(MachineState *machine,
uint32_t ramsize, hwaddr addr,
hwaddr initrd_base, hwaddr initrd_base,
hwaddr initrd_size, hwaddr initrd_size)
const char *kernel_cmdline)
{ {
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; char *filename;
int fdt_size; int fdt_size;
void *fdt; void *fdt;
@ -171,7 +162,8 @@ static int sam460ex_load_device_tree(hwaddr addr,
qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end", qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
(initrd_base + initrd_size)); (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 /* Copy data from the host device tree into the guest. Since the guest can
* directly access the timebase without host involvement, we must expose * directly access the timebase without host involvement, we must expose
@ -208,7 +200,9 @@ static int sam460ex_load_device_tree(hwaddr addr,
EBC_FREQ); EBC_FREQ);
rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr); 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; return fdt_size;
} }
@ -274,9 +268,6 @@ static void sam460ex_init(MachineState *machine)
{ {
MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *address_space_mem = get_system_memory();
MemoryRegion *isa = g_new(MemoryRegion, 1); 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); MemoryRegion *l2cache_ram = g_new(MemoryRegion, 1);
DeviceState *uic[4]; DeviceState *uic[4];
int i; int i;
@ -343,22 +334,37 @@ static void sam460ex_init(MachineState *machine)
} }
/* SDRAM controller */ /* SDRAM controller */
/* put all RAM on first bank because board has one slot /* The SoC could also handle 4 GiB but firmware does not work with that. */
* and firmware only checks that */ if (machine->ram_size > 2 * GiB) {
ppc4xx_sdram_banks(machine->ram, 1, ram_memories, ram_bases, ram_sizes, error_report("Memory over 2 GiB is not supported");
ppc460ex_sdram_bank_sizes); 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? */ /* FIXME: does 460EX have ECC interrupts? */
ppc440_sdram_init(env, SDRAM_NR_BANKS, ram_memories, /* Enable SDRAM memory regions as we may boot without firmware */
ram_bases, ram_sizes, 1); ppc4xx_sdram_ddr2_enable(PPC4xx_SDRAM_DDR2(dev));
/* IIC controllers and devices */ /* IIC controllers and devices */
dev = sysbus_create_simple(TYPE_PPC4xx_I2C, 0x4ef600700, dev = sysbus_create_simple(TYPE_PPC4xx_I2C, 0x4ef600700,
qdev_get_gpio_in(uic[0], 2)); qdev_get_gpio_in(uic[0], 2));
i2c = PPC4xx_I2C(dev)->bus; i2c = PPC4xx_I2C(dev)->bus;
/* SPD EEPROM on RAM module */ /* SPD EEPROM on RAM module */
spd_data = spd_data_generate(ram_sizes[0] < 128 * MiB ? DDR : DDR2, spd_data = spd_data_generate(machine->ram_size < 128 * MiB ? DDR : DDR2,
ram_sizes[0]); machine->ram_size);
spd_data[20] = 4; /* SO-DIMM module */ spd_data[20] = 4; /* SO-DIMM module */
smbus_eeprom_init_one(i2c, 0x50, spd_data); smbus_eeprom_init_one(i2c, 0x50, spd_data);
/* RTC */ /* RTC */
@ -496,9 +502,8 @@ static void sam460ex_init(MachineState *machine)
if (machine->kernel_filename) { if (machine->kernel_filename) {
int dt_size; int dt_size;
dt_size = sam460ex_load_device_tree(FDT_ADDR, machine->ram_size, dt_size = sam460ex_load_device_tree(machine, FDT_ADDR,
RAMDISK_ADDR, initrd_size, RAMDISK_ADDR, initrd_size);
machine->kernel_cmdline);
boot_info->dt_base = FDT_ADDR; boot_info->dt_base = FDT_ADDR;
boot_info->dt_size = dt_size; boot_info->dt_size = dt_size;

View file

@ -1713,6 +1713,9 @@ static void spapr_machine_reset(MachineState *machine)
spapr->fdt_initial_size = spapr->fdt_size; spapr->fdt_initial_size = spapr->fdt_size;
spapr->fdt_blob = fdt; spapr->fdt_blob = fdt;
/* Set machine->fdt for 'dumpdtb' QMP/HMP command */
machine->fdt = fdt;
/* Set up the entry state */ /* Set up the entry state */
first_ppc_cpu->env.gpr[5] = 0; first_ppc_cpu->env.gpr[5] = 0;

View file

@ -1256,6 +1256,14 @@ target_ulong do_client_architecture_support(PowerPCCPU *cpu,
spapr->fdt_initial_size = spapr->fdt_size; spapr->fdt_initial_size = spapr->fdt_size;
spapr->fdt_blob = fdt; 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; return H_SUCCESS;
} }

View file

@ -2045,7 +2045,7 @@ static int spapr_phb_children_reset(Object *child, void *opaque)
DeviceState *dev = (DeviceState *) object_dynamic_cast(child, TYPE_DEVICE); DeviceState *dev = (DeviceState *) object_dynamic_cast(child, TYPE_DEVICE);
if (dev) { if (dev) {
device_legacy_reset(dev); device_cold_reset(dev);
} }
return 0; return 0;

View file

@ -45,6 +45,8 @@
#include "hw/qdev-properties.h" #include "hw/qdev-properties.h"
#include "ppc405.h" #include "ppc405.h"
#include <libfdt.h>
#define EPAPR_MAGIC (0x45504150) #define EPAPR_MAGIC (0x45504150)
#define FLASH_SIZE (16 * MiB) #define FLASH_SIZE (16 * MiB)
@ -144,11 +146,10 @@ static void main_cpu_reset(void *opaque)
} }
#define BINARY_DEVICE_TREE_FILE "virtex-ml507.dtb" #define BINARY_DEVICE_TREE_FILE "virtex-ml507.dtb"
static int xilinx_load_device_tree(hwaddr addr, static int xilinx_load_device_tree(MachineState *machine,
uint32_t ramsize, hwaddr addr,
hwaddr initrd_base, hwaddr initrd_base,
hwaddr initrd_size, hwaddr initrd_size)
const char *kernel_cmdline)
{ {
char *path; char *path;
int fdt_size; int fdt_size;
@ -190,18 +191,21 @@ static int xilinx_load_device_tree(hwaddr addr,
error_report("couldn't set /chosen/linux,initrd-end"); 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) if (r < 0)
fprintf(stderr, "couldn't set /chosen/bootargs\n"); fprintf(stderr, "couldn't set /chosen/bootargs\n");
cpu_physical_memory_write(addr, fdt, fdt_size); 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; return fdt_size;
} }
static void virtex_init(MachineState *machine) static void virtex_init(MachineState *machine)
{ {
const char *kernel_filename = machine->kernel_filename; const char *kernel_filename = machine->kernel_filename;
const char *kernel_cmdline = machine->kernel_cmdline;
hwaddr initrd_base = 0; hwaddr initrd_base = 0;
int initrd_size = 0; int initrd_size = 0;
MemoryRegion *address_space_mem = get_system_memory(); 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 = high + (8192 * 2);
boot_info.fdt &= ~8191; boot_info.fdt &= ~8191;
xilinx_load_device_tree(boot_info.fdt, machine->ram_size, xilinx_load_device_tree(machine, boot_info.fdt,
initrd_base, initrd_size, initrd_base, initrd_size);
kernel_cmdline);
} }
env->load_info = &boot_info; env->load_info = &boot_info;
} }

View file

@ -634,6 +634,9 @@ static void sifive_u_machine_init(MachineState *machine)
start_addr_hi32 = (uint64_t)start_addr >> 32; start_addr_hi32 = (uint64_t)start_addr >> 32;
} }
/* Set machine->fdt for 'dumpdtb' QMP/HMP command */
machine->fdt = s->fdt;
/* reset vector */ /* reset vector */
uint32_t reset_vec[12] = { uint32_t reset_vec[12] = {
s->msel, /* MSEL pin state */ s->msel, /* MSEL pin state */

View file

@ -40,6 +40,8 @@
#include "sysemu/device_tree.h" #include "sysemu/device_tree.h"
#include "sysemu/sysemu.h" #include "sysemu/sysemu.h"
#include <libfdt.h>
static const MemMapEntry spike_memmap[] = { static const MemMapEntry spike_memmap[] = {
[SPIKE_MROM] = { 0x1000, 0xf000 }, [SPIKE_MROM] = { 0x1000, 0xf000 },
[SPIKE_HTIF] = { 0x1000000, 0x1000 }, [SPIKE_HTIF] = { 0x1000000, 0x1000 },
@ -304,6 +306,10 @@ static void spike_board_init(MachineState *machine)
/* Compute the fdt load address in dram */ /* Compute the fdt load address in dram */
fdt_load_addr = riscv_load_fdt(memmap[SPIKE_DRAM].base, fdt_load_addr = riscv_load_fdt(memmap[SPIKE_DRAM].base,
machine->ram_size, s->fdt); machine->ram_size, s->fdt);
/* Set machine->fdt for 'dumpdtb' QMP/HMP command */
machine->fdt = s->fdt;
/* load the reset vector */ /* load the reset vector */
riscv_setup_rom_reset_vec(machine, &s->soc[0], memmap[SPIKE_DRAM].base, riscv_setup_rom_reset_vec(machine, &s->soc[0], memmap[SPIKE_DRAM].base,
memmap[SPIKE_MROM].base, memmap[SPIKE_MROM].base,

View file

@ -29,16 +29,17 @@
#include "exec/memory.h" #include "exec/memory.h"
#include "hw/sysbus.h" #include "hw/sysbus.h"
void ppc4xx_sdram_banks(MemoryRegion *ram, int nr_banks, typedef struct {
MemoryRegion ram_memories[], MemoryRegion ram;
hwaddr ram_bases[], hwaddr ram_sizes[], MemoryRegion container; /* used for clipping */
const ram_addr_t sdram_bank_sizes[]); hwaddr base;
hwaddr size;
uint32_t bcr;
} Ppc4xxSdramBank;
void ppc4xx_sdram_init (CPUPPCState *env, qemu_irq irq, int nbanks, void ppc4xx_sdram_banks(MemoryRegion *ram, int nr_banks,
MemoryRegion ram_memories[], Ppc4xxSdramBank ram_banks[],
hwaddr *ram_bases, const ram_addr_t sdram_bank_sizes[]);
hwaddr *ram_sizes,
int do_init);
#define TYPE_PPC4xx_PCI_HOST_BRIDGE "ppc4xx-pcihost" #define TYPE_PPC4xx_PCI_HOST_BRIDGE "ppc4xx-pcihost"
@ -109,4 +110,50 @@ struct Ppc4xxEbcState {
uint32_t cfg; 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 */ #endif /* PPC4XX_H */

View file

@ -136,6 +136,7 @@ int qemu_fdt_add_path(void *fdt, const char *path);
} while (0) } while (0)
void qemu_fdt_dumpdtb(void *fdt, int size); void qemu_fdt_dumpdtb(void *fdt, int size);
void hmp_dumpdtb(Monitor *mon, const QDict *qdict);
/** /**
* qemu_fdt_setprop_sized_cells_from_array: * qemu_fdt_setprop_sized_cells_from_array:

View file

@ -49,6 +49,7 @@
#include "sysemu/blockdev.h" #include "sysemu/blockdev.h"
#include "sysemu/sysemu.h" #include "sysemu/sysemu.h"
#include "sysemu/tpm.h" #include "sysemu/tpm.h"
#include "sysemu/device_tree.h"
#include "qapi/qmp/qdict.h" #include "qapi/qmp/qdict.h"
#include "qapi/qmp/qerror.h" #include "qapi/qmp/qerror.h"
#include "qapi/qmp/qstring.h" #include "qapi/qmp/qstring.h"

View file

@ -1664,3 +1664,21 @@
'*size': 'size', '*size': 'size',
'*max-size': 'size', '*max-size': 'size',
'*slots': 'uint64' } } '*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' }

View file

@ -26,6 +26,9 @@
#include "hw/loader.h" #include "hw/loader.h"
#include "hw/boards.h" #include "hw/boards.h"
#include "qemu/config-file.h" #include "qemu/config-file.h"
#include "qapi/qapi-commands-machine.h"
#include "qapi/qmp/qdict.h"
#include "monitor/hmp.h"
#include <libfdt.h> #include <libfdt.h>
@ -643,3 +646,37 @@ out:
g_free(propcells); g_free(propcells);
return ret; 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);
}

View file

@ -1247,6 +1247,12 @@ static void powerpc_excp_booke(PowerPCCPU *cpu, int excp)
case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable/VPU */ case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable/VPU */
env->spr[SPR_BOOKE_ESR] = ESR_SPV; env->spr[SPR_BOOKE_ESR] = ESR_SPV;
break; 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 */ case POWERPC_EXCP_RESET: /* System reset exception */
if (FIELD_EX64(env->msr, MSR, POW)) { if (FIELD_EX64(env->msr, MSR, POW)) {
cpu_abort(cs, "Trying to deliver power-saving system reset " cpu_abort(cs, "Trying to deliver power-saving system reset "

View file

@ -810,7 +810,6 @@ static void gen_##name(DisasContext *ctx) \
gen_helper_##name(ignored, cpu_env, xt, xa, xb); \ gen_helper_##name(ignored, cpu_env, xt, xa, xb); \
tcg_temp_free_i32(ignored); \ tcg_temp_free_i32(ignored); \
} \ } \
gen_helper_float_check_status(cpu_env); \
tcg_temp_free_ptr(xt); \ tcg_temp_free_ptr(xt); \
tcg_temp_free_ptr(xa); \ tcg_temp_free_ptr(xa); \
tcg_temp_free_ptr(xb); \ tcg_temp_free_ptr(xb); \