aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorStefan Hajnoczi <stefanha@redhat.com>2022-10-31 06:28:43 -0400
committerStefan Hajnoczi <stefanha@redhat.com>2022-10-31 06:28:43 -0400
commit179938097df4de34b13527ad1fd469f501548b07 (patch)
treef18f1182b784086b1c35c3ef7f0caf8c4f17fd4d /hw
parent395a90be6f0af51732540c5e632c0fe49222e28c (diff)
parentfb22d743b93b49b73930aff40d3ba9d252f81a56 (diff)
downloadqemu-179938097df4de34b13527ad1fd469f501548b07.zip
qemu-179938097df4de34b13527ad1fd469f501548b07.tar.gz
qemu-179938097df4de34b13527ad1fd469f501548b07.tar.bz2
Merge tag 'pull-ppc-20221029' of https://gitlab.com/danielhb/qemu into staging
ppc patch queue for 2022-10-29: This queue has the second part of the ppc4xx_sdram cleanups, doorbell instructions for POWER8, new pflash handling for the e500 machine and a Radix MMU regression fix. It also has a lot of performance optimizations in the PowerPC emulation done by the researchers of the Eldorado institute. Between using gvec for VMX/VSX instructions, a full rework of the interrupt model and PMU optimizations, they managed to drastically speed up the emulation of powernv8/9/10 machines. Here's an example with avocado tests: - with master: tests/avocado/boot_linux_console.py:BootLinuxConsole.test_ppc_powernv8: PASS (38.89 s) tests/avocado/boot_linux_console.py:BootLinuxConsole.test_ppc_powernv9: PASS (43.89 s) - with this queue applied: tests/avocado/boot_linux_console.py:BootLinuxConsole.test_ppc_powernv8: PASS (21.23 s) tests/avocado/boot_linux_console.py:BootLinuxConsole.test_ppc_powernv9: PASS (22.58 s) Other ppc machines, like pseries, also had a noticeable performance boost. # -----BEGIN PGP SIGNATURE----- # # iHUEABYKAB0WIQQX6/+ZI9AYAK8oOBk82cqW3gMxZAUCY10J/gAKCRA82cqW3gMx # ZAbjAPwKNbE1wE2POJbMALBQAM5MewwLMV/UKGjE6jA7HAbb/AEA9e3o11FoUmSJ # rZkmTvMzBQZ81mMGRlS0cnqbrr4ADgc= # =gnKY # -----END PGP SIGNATURE----- # gpg: Signature made Sat 29 Oct 2022 07:09:50 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-20221029' of https://gitlab.com/danielhb/qemu: (63 commits) target/ppc: Fix regression in Radix MMU hw/ppc/e500: Implement pflash handling hw/sd/sdhci: Rename ESDHC_* defines to USDHC_* hw/sd/sdhci-internal: Unexport ESDHC defines hw/block/pflash_cfi0{1, 2}: Error out if device length isn't a power of two docs/system/ppc/ppce500: Use qemu-system-ppc64 across the board(s) target/ppc: Increment PMC5 with inline insns target/ppc: Add new PMC HFLAGS ppc4xx_sdram: Add errp parameter to ppc4xx_sdram_banks() ppc4xx_sdram: Convert DDR SDRAM controller to new bank handling ppc4xx_sdram: Generalise bank setup ppc4xx_sdram: Rename local state variable for brevity ppc4xx_sdram: Use hwaddr for memory bank size ppc4xx_sdram: Move ppc4xx_sdram_banks() to ppc4xx_sdram.c ppc4xx_devs.c: Move DDR SDRAM controller model to ppc4xx_sdram.c ppc440_uc.c: Move DDR2 SDRAM controller model to ppc4xx_sdram.c target/ppc: move the p*_interrupt_powersave methods to excp_helper.c target/ppc: unify cpu->has_work based on cs->interrupt_request target/ppc: introduce ppc_maybe_interrupt target/ppc: remove ppc_store_lpcr from CONFIG_USER_ONLY builds ... Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Diffstat (limited to 'hw')
-rw-r--r--hw/block/pflash_cfi01.c8
-rw-r--r--hw/block/pflash_cfi02.c5
-rw-r--r--hw/ppc/Kconfig1
-rw-r--r--hw/ppc/e500.c79
-rw-r--r--hw/ppc/meson.build3
-rw-r--r--hw/ppc/pnv_core.c1
-rw-r--r--hw/ppc/ppc.c17
-rw-r--r--hw/ppc/ppc440_uc.c332
-rw-r--r--hw/ppc/ppc4xx_devs.c414
-rw-r--r--hw/ppc/ppc4xx_sdram.c757
-rw-r--r--hw/ppc/spapr_hcall.c6
-rw-r--r--hw/ppc/spapr_rtas.c2
-rw-r--r--hw/ppc/trace-events3
-rw-r--r--hw/sd/sdhci-internal.h20
-rw-r--r--hw/sd/sdhci.c63
15 files changed, 907 insertions, 804 deletions
diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c
index 0cbc2fb..9c235bf 100644
--- a/hw/block/pflash_cfi01.c
+++ b/hw/block/pflash_cfi01.c
@@ -690,7 +690,7 @@ static const MemoryRegionOps pflash_cfi01_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
-static void pflash_cfi01_fill_cfi_table(PFlashCFI01 *pfl)
+static void pflash_cfi01_fill_cfi_table(PFlashCFI01 *pfl, Error **errp)
{
uint64_t blocks_per_device, sector_len_per_device, device_len;
int num_devices;
@@ -708,6 +708,10 @@ static void pflash_cfi01_fill_cfi_table(PFlashCFI01 *pfl)
sector_len_per_device = pfl->sector_len / num_devices;
}
device_len = sector_len_per_device * blocks_per_device;
+ if (!is_power_of_2(device_len)) {
+ error_setg(errp, "Device size must be a power of two.");
+ return;
+ }
/* Hardcoded CFI table */
/* Standard "QRY" string */
@@ -865,7 +869,7 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp)
*/
pfl->cmd = 0x00;
pfl->status = 0x80; /* WSM ready */
- pflash_cfi01_fill_cfi_table(pfl);
+ pflash_cfi01_fill_cfi_table(pfl, errp);
}
static void pflash_cfi01_system_reset(DeviceState *dev)
diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
index 2a99b28..ff2fe15 100644
--- a/hw/block/pflash_cfi02.c
+++ b/hw/block/pflash_cfi02.c
@@ -880,6 +880,11 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
return;
}
+ if (!is_power_of_2(pfl->chip_len)) {
+ error_setg(errp, "Device size must be a power of two.");
+ return;
+ }
+
memory_region_init_rom_device(&pfl->orig_mem, OBJECT(pfl),
&pflash_cfi02_ops, pfl, pfl->name,
pfl->chip_len, errp);
diff --git a/hw/ppc/Kconfig b/hw/ppc/Kconfig
index 791fe78..769a1ea 100644
--- a/hw/ppc/Kconfig
+++ b/hw/ppc/Kconfig
@@ -126,6 +126,7 @@ config E500
select ETSEC
select GPIO_MPC8XXX
select OPENPIC
+ select PFLASH_CFI01
select PLATFORM_BUS
select PPCE500_PCI
select SERIAL
diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index 3e950ea..2fe4966 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -23,8 +23,10 @@
#include "e500-ccsr.h"
#include "net/net.h"
#include "qemu/config-file.h"
+#include "hw/block/flash.h"
#include "hw/char/serial.h"
#include "hw/pci/pci.h"
+#include "sysemu/block-backend-io.h"
#include "sysemu/sysemu.h"
#include "sysemu/kvm.h"
#include "sysemu/reset.h"
@@ -267,6 +269,31 @@ static void sysbus_device_create_devtree(SysBusDevice *sbdev, void *opaque)
}
}
+static void create_devtree_flash(SysBusDevice *sbdev,
+ PlatformDevtreeData *data)
+{
+ g_autofree char *name = NULL;
+ uint64_t num_blocks = object_property_get_uint(OBJECT(sbdev),
+ "num-blocks",
+ &error_fatal);
+ uint64_t sector_length = object_property_get_uint(OBJECT(sbdev),
+ "sector-length",
+ &error_fatal);
+ uint64_t bank_width = object_property_get_uint(OBJECT(sbdev),
+ "width",
+ &error_fatal);
+ hwaddr flashbase = 0;
+ hwaddr flashsize = num_blocks * sector_length;
+ void *fdt = data->fdt;
+
+ name = g_strdup_printf("%s/nor@%" PRIx64, data->node, flashbase);
+ qemu_fdt_add_subnode(fdt, name);
+ qemu_fdt_setprop_string(fdt, name, "compatible", "cfi-flash");
+ qemu_fdt_setprop_sized_cells(fdt, name, "reg",
+ 1, flashbase, 1, flashsize);
+ qemu_fdt_setprop_cell(fdt, name, "bank-width", bank_width);
+}
+
static void platform_bus_create_devtree(PPCE500MachineState *pms,
void *fdt, const char *mpic)
{
@@ -276,6 +303,8 @@ static void platform_bus_create_devtree(PPCE500MachineState *pms,
uint64_t addr = pmc->platform_bus_base;
uint64_t size = pmc->platform_bus_size;
int irq_start = pmc->platform_bus_first_irq;
+ SysBusDevice *sbdev;
+ bool ambiguous;
/* Create a /platform node that we can put all devices into */
@@ -302,6 +331,13 @@ static void platform_bus_create_devtree(PPCE500MachineState *pms,
/* Loop through all dynamic sysbus devices and create nodes for them */
foreach_dynamic_sysbus_device(sysbus_device_create_devtree, &data);
+ sbdev = SYS_BUS_DEVICE(object_resolve_path_type("", TYPE_PFLASH_CFI01,
+ &ambiguous));
+ if (sbdev) {
+ assert(!ambiguous);
+ create_devtree_flash(sbdev, &data);
+ }
+
g_free(node);
}
@@ -856,6 +892,7 @@ void ppce500_init(MachineState *machine)
unsigned int pci_irq_nrs[PCI_NUM_PINS] = {1, 2, 3, 4};
IrqLines *irqs;
DeviceState *dev, *mpicdev;
+ DriveInfo *dinfo;
CPUPPCState *firstenv = NULL;
MemoryRegion *ccsr_addr_space;
SysBusDevice *s;
@@ -1024,6 +1061,48 @@ void ppce500_init(MachineState *machine)
pmc->platform_bus_base,
&pms->pbus_dev->mmio);
+ dinfo = drive_get(IF_PFLASH, 0, 0);
+ if (dinfo) {
+ BlockBackend *blk = blk_by_legacy_dinfo(dinfo);
+ BlockDriverState *bs = blk_bs(blk);
+ uint64_t mmio_size = memory_region_size(&pms->pbus_dev->mmio);
+ uint64_t size = bdrv_getlength(bs);
+ uint32_t sector_len = 64 * KiB;
+
+ if (!is_power_of_2(size)) {
+ error_report("Size of pflash file must be a power of two.");
+ exit(1);
+ }
+
+ if (size > mmio_size) {
+ error_report("Size of pflash file must not be bigger than %" PRIu64
+ " bytes.", mmio_size);
+ exit(1);
+ }
+
+ if (!QEMU_IS_ALIGNED(size, sector_len)) {
+ error_report("Size of pflash file must be a multiple of %" PRIu32
+ ".", sector_len);
+ exit(1);
+ }
+
+ dev = qdev_new(TYPE_PFLASH_CFI01);
+ qdev_prop_set_drive(dev, "drive", blk);
+ qdev_prop_set_uint32(dev, "num-blocks", size / sector_len);
+ qdev_prop_set_uint64(dev, "sector-length", sector_len);
+ qdev_prop_set_uint8(dev, "width", 2);
+ qdev_prop_set_bit(dev, "big-endian", true);
+ qdev_prop_set_uint16(dev, "id0", 0x89);
+ qdev_prop_set_uint16(dev, "id1", 0x18);
+ qdev_prop_set_uint16(dev, "id2", 0x0000);
+ qdev_prop_set_uint16(dev, "id3", 0x0);
+ qdev_prop_set_string(dev, "name", "e500.flash");
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+
+ memory_region_add_subregion(&pms->pbus_dev->mmio, 0,
+ pflash_cfi01_get_memory(PFLASH_CFI01(dev)));
+ }
+
/*
* Smart firmware defaults ahead!
*
diff --git a/hw/ppc/meson.build b/hw/ppc/meson.build
index 32babc9..c927337 100644
--- a/hw/ppc/meson.build
+++ b/hw/ppc/meson.build
@@ -59,8 +59,9 @@ ppc_ss.add(when: 'CONFIG_PPC440', if_true: files(
'ppc440_bamboo.c',
'ppc440_pcix.c', 'ppc440_uc.c'))
ppc_ss.add(when: 'CONFIG_PPC4XX', if_true: files(
+ 'ppc4xx_devs.c',
'ppc4xx_pci.c',
- 'ppc4xx_devs.c'))
+ 'ppc4xx_sdram.c'))
ppc_ss.add(when: 'CONFIG_SAM460EX', if_true: files('sam460ex.c'))
# PReP
ppc_ss.add(when: 'CONFIG_PREP', if_true: files('prep.c'))
diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
index 19e8eb8..9ee7919 100644
--- a/hw/ppc/pnv_core.c
+++ b/hw/ppc/pnv_core.c
@@ -58,6 +58,7 @@ static void pnv_core_cpu_reset(PnvCore *pc, PowerPCCPU *cpu)
env->msr |= MSR_HVB; /* Hypervisor mode */
env->spr[SPR_HRMOR] = pc->hrmor;
hreg_compute_hflags(env);
+ ppc_maybe_interrupt(env);
pcc->intc_reset(pc->chip, cpu);
}
diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c
index 690f448..dc86c1c 100644
--- a/hw/ppc/ppc.c
+++ b/hw/ppc/ppc.c
@@ -40,9 +40,8 @@
static void cpu_ppc_tb_stop (CPUPPCState *env);
static void cpu_ppc_tb_start (CPUPPCState *env);
-void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level)
+void ppc_set_irq(PowerPCCPU *cpu, int irq, int level)
{
- CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
unsigned int old_pending;
bool locked = false;
@@ -56,21 +55,17 @@ void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level)
old_pending = env->pending_interrupts;
if (level) {
- env->pending_interrupts |= 1 << n_IRQ;
- cpu_interrupt(cs, CPU_INTERRUPT_HARD);
+ env->pending_interrupts |= irq;
} else {
- env->pending_interrupts &= ~(1 << n_IRQ);
- if (env->pending_interrupts == 0) {
- cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
- }
+ env->pending_interrupts &= ~irq;
}
if (old_pending != env->pending_interrupts) {
- kvmppc_set_interrupt(cpu, n_IRQ, level);
+ ppc_maybe_interrupt(env);
+ kvmppc_set_interrupt(cpu, irq, level);
}
-
- trace_ppc_irq_set_exit(env, n_IRQ, level, env->pending_interrupts,
+ trace_ppc_irq_set_exit(env, irq, level, env->pending_interrupts,
CPU(cpu)->interrupt_request);
if (locked) {
diff --git a/hw/ppc/ppc440_uc.c b/hw/ppc/ppc440_uc.c
index 5fbf440..6512639 100644
--- a/hw/ppc/ppc440_uc.c
+++ b/hw/ppc/ppc440_uc.c
@@ -10,21 +10,14 @@
#include "qemu/osdep.h"
#include "qemu/units.h"
-#include "qemu/error-report.h"
#include "qapi/error.h"
#include "qemu/log.h"
-#include "qemu/module.h"
#include "hw/irq.h"
-#include "exec/memory.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 */
@@ -479,331 +472,6 @@ void ppc4xx_sdr_init(CPUPPCState *env)
}
/*****************************************************************************/
-/* SDRAM controller */
-enum {
- SDRAM0_CFGADDR = 0x10,
- SDRAM0_CFGDATA,
- SDRAM_R0BAS = 0x40,
- SDRAM_R1BAS,
- SDRAM_R2BAS,
- SDRAM_R3BAS,
- SDRAM_CONF1HB = 0x45,
- SDRAM_PLBADDULL = 0x4a,
- SDRAM_CONF1LL = 0x4b,
- SDRAM_CONFPATHB = 0x4f,
- SDRAM_PLBADDUHB = 0x50,
-};
-
-static uint32_t sdram_ddr2_bcr(hwaddr ram_base, hwaddr ram_size)
-{
- uint32_t bcr;
-
- switch (ram_size) {
- case 8 * MiB:
- bcr = 0xffc0;
- break;
- case 16 * MiB:
- bcr = 0xff80;
- break;
- case 32 * MiB:
- bcr = 0xff00;
- break;
- case 64 * MiB:
- bcr = 0xfe00;
- break;
- case 128 * MiB:
- bcr = 0xfc00;
- break;
- case 256 * MiB:
- bcr = 0xf800;
- break;
- case 512 * MiB:
- bcr = 0xf000;
- break;
- case 1 * GiB:
- bcr = 0xe000;
- break;
- case 2 * GiB:
- bcr = 0xc000;
- break;
- case 4 * GiB:
- bcr = 0x8000;
- break;
- default:
- error_report("invalid RAM size " TARGET_FMT_plx, ram_size);
- return 0;
- }
- bcr |= ram_base >> 2 & 0xffe00000;
- bcr |= 1;
-
- return bcr;
-}
-
-static inline hwaddr sdram_ddr2_base(uint32_t bcr)
-{
- return (bcr & 0xffe00000) << 2;
-}
-
-static uint64_t sdram_ddr2_size(uint32_t bcr)
-{
- uint64_t size;
- int sh;
-
- sh = 1024 - ((bcr >> 6) & 0x3ff);
- size = 8 * MiB * sh;
-
- return size;
-}
-
-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->bank[i].bcr & 1) {
- /* First unmap RAM if enabled */
- 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->bank[i].bcr = bcr & 0xffe0ffc1;
- if (enabled && (bcr & 1)) {
- trace_ppc4xx_sdram_map(sdram_ddr2_base(bcr), sdram_ddr2_size(bcr));
- sdram_bank_map(&sdram->bank[i]);
- }
-}
-
-static void sdram_ddr2_map_bcr(Ppc4xxSdramDdr2State *sdram)
-{
- int i;
-
- for (i = 0; i < sdram->nbanks; i++) {
- 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_ddr2_set_bcr(sdram, i, 0, 0);
- }
- }
-}
-
-static void sdram_ddr2_unmap_bcr(Ppc4xxSdramDdr2State *sdram)
-{
- 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) {
- case SDRAM_R0BAS:
- case SDRAM_R1BAS:
- case SDRAM_R2BAS:
- case SDRAM_R3BAS:
- 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:
- case SDRAM_CONF1LL:
- case SDRAM_CONFPATHB:
- case SDRAM_PLBADDULL:
- case SDRAM_PLBADDUHB:
- break;
- case SDRAM0_CFGADDR:
- ret = sdram->addr;
- break;
- case SDRAM0_CFGDATA:
- switch (sdram->addr) {
- case 0x14: /* SDRAM_MCSTAT (405EX) */
- case 0x1F:
- ret = 0x80000000;
- break;
- case 0x21: /* SDRAM_MCOPT2 */
- ret = sdram->mcopt2;
- break;
- case 0x40: /* SDRAM_MB0CF */
- ret = 0x00008001;
- break;
- case 0x7A: /* SDRAM_DLCR */
- ret = 0x02000000;
- break;
- case 0xE1: /* SDR0_DDR0 */
- ret = SDR0_DDR0_DDRM_ENCODE(1) | SDR0_DDR0_DDRM_DDR1;
- break;
- default:
- break;
- }
- break;
- default:
- break;
- }
-
- return ret;
-}
-
-#define SDRAM_DDR2_MCOPT2_DCEN BIT(27)
-
-static void sdram_ddr2_dcr_write(void *opaque, int dcrn, uint32_t val)
-{
- Ppc4xxSdramDdr2State *sdram = opaque;
-
- switch (dcrn) {
- case SDRAM_R0BAS:
- case SDRAM_R1BAS:
- case SDRAM_R2BAS:
- case SDRAM_R3BAS:
- case SDRAM_CONF1HB:
- case SDRAM_CONF1LL:
- case SDRAM_CONFPATHB:
- case SDRAM_PLBADDULL:
- case SDRAM_PLBADDUHB:
- break;
- case SDRAM0_CFGADDR:
- sdram->addr = val;
- break;
- case SDRAM0_CFGDATA:
- 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;
- }
- break;
- default:
- break;
- }
-}
-
-static void ppc4xx_sdram_ddr2_reset(DeviceState *dev)
-{
- Ppc4xxSdramDdr2State *sdram = PPC4xx_SDRAM_DDR2(dev);
-
- sdram->addr = 0;
- sdram->mcopt2 = 0;
-}
-
-static void ppc4xx_sdram_ddr2_realize(DeviceState *dev, Error **errp)
-{
- 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);
-
- 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 {
AHB_TOP = 0xA4,
diff --git a/hw/ppc/ppc4xx_devs.c b/hw/ppc/ppc4xx_devs.c
index 12af90f..c1d1114 100644
--- a/hw/ppc/ppc4xx_devs.c
+++ b/hw/ppc/ppc4xx_devs.c
@@ -23,419 +23,10 @@
*/
#include "qemu/osdep.h"
-#include "qemu/units.h"
-#include "sysemu/reset.h"
#include "cpu.h"
-#include "hw/irq.h"
-#include "hw/ppc/ppc.h"
#include "hw/ppc/ppc4xx.h"
#include "hw/qdev-properties.h"
-#include "qemu/log.h"
-#include "exec/address-spaces.h"
-#include "qemu/error-report.h"
#include "qapi/error.h"
-#include "trace.h"
-
-/*****************************************************************************/
-/* SDRAM controller */
-enum {
- SDRAM0_CFGADDR = 0x010,
- SDRAM0_CFGDATA = 0x011,
-};
-
-/*
- * XXX: TOFIX: some patches have made this code become inconsistent:
- * there are type inconsistencies, mixing hwaddr, target_ulong
- * and uint32_t
- */
-static uint32_t sdram_ddr_bcr(hwaddr ram_base, hwaddr ram_size)
-{
- uint32_t bcr;
-
- switch (ram_size) {
- case 4 * MiB:
- bcr = 0;
- break;
- case 8 * MiB:
- bcr = 0x20000;
- break;
- case 16 * MiB:
- bcr = 0x40000;
- break;
- case 32 * MiB:
- bcr = 0x60000;
- break;
- case 64 * MiB:
- bcr = 0x80000;
- break;
- case 128 * MiB:
- bcr = 0xA0000;
- break;
- case 256 * MiB:
- bcr = 0xC0000;
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "%s: invalid RAM size 0x%" HWADDR_PRIx "\n", __func__,
- ram_size);
- return 0;
- }
- bcr |= ram_base & 0xFF800000;
- bcr |= 1;
-
- return bcr;
-}
-
-static inline hwaddr sdram_ddr_base(uint32_t bcr)
-{
- return bcr & 0xFF800000;
-}
-
-static target_ulong sdram_ddr_size(uint32_t bcr)
-{
- target_ulong size;
- int sh;
-
- sh = (bcr >> 17) & 0x7;
- if (sh == 7) {
- size = -1;
- } else {
- size = (4 * MiB) << sh;
- }
-
- return size;
-}
-
-static void sdram_ddr_set_bcr(Ppc4xxSdramDdrState *sdram, int i,
- uint32_t bcr, int enabled)
-{
- if (sdram->bank[i].bcr & 1) {
- /* Unmap RAM */
- 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->bank[i].container);
- memory_region_del_subregion(&sdram->bank[i].container,
- &sdram->bank[i].ram);
- object_unparent(OBJECT(&sdram->bank[i].container));
- }
- 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_ddr_base(bcr),
- &sdram->bank[i].container);
- }
-}
-
-static void sdram_ddr_map_bcr(Ppc4xxSdramDdrState *sdram)
-{
- int i;
-
- for (i = 0; i < sdram->nbanks; i++) {
- 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_ddr_set_bcr(sdram, i, 0, 0);
- }
- }
-}
-
-static void sdram_ddr_unmap_bcr(Ppc4xxSdramDdrState *sdram)
-{
- int i;
-
- for (i = 0; i < sdram->nbanks; 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->bank[i].ram);
- }
-}
-
-static uint32_t sdram_ddr_dcr_read(void *opaque, int dcrn)
-{
- Ppc4xxSdramDdrState *sdram = opaque;
- uint32_t ret;
-
- switch (dcrn) {
- case SDRAM0_CFGADDR:
- ret = sdram->addr;
- break;
- case SDRAM0_CFGDATA:
- switch (sdram->addr) {
- case 0x00: /* SDRAM_BESR0 */
- ret = sdram->besr0;
- break;
- case 0x08: /* SDRAM_BESR1 */
- ret = sdram->besr1;
- break;
- case 0x10: /* SDRAM_BEAR */
- ret = sdram->bear;
- break;
- case 0x20: /* SDRAM_CFG */
- ret = sdram->cfg;
- break;
- case 0x24: /* SDRAM_STATUS */
- ret = sdram->status;
- break;
- case 0x30: /* SDRAM_RTR */
- ret = sdram->rtr;
- break;
- case 0x34: /* SDRAM_PMIT */
- ret = sdram->pmit;
- break;
- case 0x40: /* SDRAM_B0CR */
- ret = sdram->bank[0].bcr;
- break;
- case 0x44: /* SDRAM_B1CR */
- ret = sdram->bank[1].bcr;
- break;
- case 0x48: /* SDRAM_B2CR */
- ret = sdram->bank[2].bcr;
- break;
- case 0x4C: /* SDRAM_B3CR */
- ret = sdram->bank[3].bcr;
- break;
- case 0x80: /* SDRAM_TR */
- ret = -1; /* ? */
- break;
- case 0x94: /* SDRAM_ECCCFG */
- ret = sdram->ecccfg;
- break;
- case 0x98: /* SDRAM_ECCESR */
- ret = sdram->eccesr;
- break;
- default: /* Error */
- ret = -1;
- break;
- }
- break;
- default:
- /* Avoid gcc warning */
- ret = 0;
- break;
- }
-
- return ret;
-}
-
-static void sdram_ddr_dcr_write(void *opaque, int dcrn, uint32_t val)
-{
- Ppc4xxSdramDdrState *sdram = opaque;
-
- switch (dcrn) {
- case SDRAM0_CFGADDR:
- sdram->addr = val;
- break;
- case SDRAM0_CFGDATA:
- switch (sdram->addr) {
- case 0x00: /* SDRAM_BESR0 */
- sdram->besr0 &= ~val;
- break;
- case 0x08: /* SDRAM_BESR1 */
- sdram->besr1 &= ~val;
- break;
- case 0x10: /* SDRAM_BEAR */
- sdram->bear = val;
- break;
- case 0x20: /* SDRAM_CFG */
- val &= 0xFFE00000;
- if (!(sdram->cfg & 0x80000000) && (val & 0x80000000)) {
- trace_ppc4xx_sdram_enable("enable");
- /* validate all RAM mappings */
- 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_ddr_unmap_bcr(sdram);
- sdram->status |= 0x80000000;
- }
- if (!(sdram->cfg & 0x40000000) && (val & 0x40000000)) {
- sdram->status |= 0x40000000;
- } else if ((sdram->cfg & 0x40000000) && !(val & 0x40000000)) {
- sdram->status &= ~0x40000000;
- }
- sdram->cfg = val;
- break;
- case 0x24: /* SDRAM_STATUS */
- /* Read-only register */
- break;
- case 0x30: /* SDRAM_RTR */
- sdram->rtr = val & 0x3FF80000;
- break;
- case 0x34: /* SDRAM_PMIT */
- sdram->pmit = (val & 0xF8000000) | 0x07C00000;
- break;
- case 0x40: /* SDRAM_B0CR */
- sdram_ddr_set_bcr(sdram, 0, val, sdram->cfg & 0x80000000);
- break;
- case 0x44: /* SDRAM_B1CR */
- sdram_ddr_set_bcr(sdram, 1, val, sdram->cfg & 0x80000000);
- break;
- case 0x48: /* SDRAM_B2CR */
- sdram_ddr_set_bcr(sdram, 2, val, sdram->cfg & 0x80000000);
- break;
- case 0x4C: /* SDRAM_B3CR */
- sdram_ddr_set_bcr(sdram, 3, val, sdram->cfg & 0x80000000);
- break;
- case 0x80: /* SDRAM_TR */
- sdram->tr = val & 0x018FC01F;
- break;
- case 0x94: /* SDRAM_ECCCFG */
- sdram->ecccfg = val & 0x00F00000;
- break;
- case 0x98: /* SDRAM_ECCESR */
- val &= 0xFFF0F000;
- if (sdram->eccesr == 0 && val != 0) {
- qemu_irq_raise(sdram->irq);
- } else if (sdram->eccesr != 0 && val == 0) {
- qemu_irq_lower(sdram->irq);
- }
- sdram->eccesr = val;
- break;
- default: /* Error */
- break;
- }
- break;
- }
-}
-
-static void ppc4xx_sdram_ddr_reset(DeviceState *dev)
-{
- 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 = 0;
- sdram->cfg = 0x00800000;
-}
-
-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);
-}
-
-/*
- * Split RAM between SDRAM banks.
- *
- * sdram_bank_sizes[] must be in descending order, that is sizes[i] > sizes[i+1]
- * and must be 0-terminated.
- *
- * The 4xx SDRAM controller supports a small number of banks, and each bank
- * must be one of a small set of sizes. The number of banks and the supported
- * sizes varies by SoC.
- */
-void ppc4xx_sdram_banks(MemoryRegion *ram, int nr_banks,
- Ppc4xxSdramBank ram_banks[],
- const ram_addr_t sdram_bank_sizes[])
-{
- ram_addr_t size_left = memory_region_size(ram);
- ram_addr_t base = 0;
- ram_addr_t bank_size;
- int i;
- int j;
-
- for (i = 0; i < nr_banks; i++) {
- for (j = 0; sdram_bank_sizes[j] != 0; j++) {
- bank_size = sdram_bank_sizes[j];
- if (bank_size <= size_left) {
- char name[32];
-
- 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_banks[i].ram, NULL, name, ram,
- ram_banks[i].base, ram_banks[i].size);
- break;
- }
- }
- if (!size_left) {
- /* No need to use the remaining banks. */
- break;
- }
- }
-
- if (size_left) {
- ram_addr_t used_size = memory_region_size(ram) - size_left;
- GString *s = g_string_new(NULL);
-
- for (i = 0; sdram_bank_sizes[i]; i++) {
- g_string_append_printf(s, "%" PRIi64 "%s",
- sdram_bank_sizes[i] / MiB,
- sdram_bank_sizes[i + 1] ? ", " : "");
- }
- error_report("at most %d bank%s of %s MiB each supported",
- nr_banks, nr_banks == 1 ? "" : "s", s->str);
- error_printf("Possible valid RAM size: %" PRIi64 " MiB\n",
- used_size ? used_size / MiB : sdram_bank_sizes[i - 1] / MiB);
-
- g_string_free(s, true);
- exit(EXIT_FAILURE);
- }
-}
/*****************************************************************************/
/* MAL */
@@ -963,11 +554,6 @@ 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/ppc4xx_sdram.c b/hw/ppc/ppc4xx_sdram.c
new file mode 100644
index 0000000..8d7137f
--- /dev/null
+++ b/hw/ppc/ppc4xx_sdram.c
@@ -0,0 +1,757 @@
+/*
+ * QEMU PowerPC 4xx embedded processors SDRAM controller emulation
+ *
+ * DDR SDRAM controller:
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * DDR2 SDRAM controller:
+ * Copyright (c) 2012 François Revol
+ * Copyright (c) 2016-2019 BALATON Zoltan
+ *
+ * This work is licensed under the GNU GPL license version 2 or later.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/units.h"
+#include "qapi/error.h"
+#include "qemu/log.h"
+#include "exec/address-spaces.h" /* get_system_memory() */
+#include "hw/irq.h"
+#include "hw/qdev-properties.h"
+#include "hw/ppc/ppc4xx.h"
+#include "trace.h"
+
+/*****************************************************************************/
+/* Shared functions */
+
+/*
+ * Split RAM between SDRAM banks.
+ *
+ * sdram_bank_sizes[] must be in descending order, that is sizes[i] > sizes[i+1]
+ * and must be 0-terminated.
+ *
+ * The 4xx SDRAM controller supports a small number of banks, and each bank
+ * must be one of a small set of sizes. The number of banks and the supported
+ * sizes varies by SoC.
+ */
+static bool ppc4xx_sdram_banks(MemoryRegion *ram, int nr_banks,
+ Ppc4xxSdramBank ram_banks[],
+ const ram_addr_t sdram_bank_sizes[],
+ Error **errp)
+{
+ ERRP_GUARD();
+ ram_addr_t size_left = memory_region_size(ram);
+ ram_addr_t base = 0;
+ ram_addr_t bank_size;
+ int i;
+ int j;
+
+ for (i = 0; i < nr_banks; i++) {
+ for (j = 0; sdram_bank_sizes[j] != 0; j++) {
+ bank_size = sdram_bank_sizes[j];
+ if (bank_size <= size_left) {
+ char name[32];
+
+ 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_banks[i].ram, NULL, name, ram,
+ ram_banks[i].base, ram_banks[i].size);
+ break;
+ }
+ }
+ if (!size_left) {
+ /* No need to use the remaining banks. */
+ break;
+ }
+ }
+
+ if (size_left) {
+ ram_addr_t used_size = memory_region_size(ram) - size_left;
+ GString *s = g_string_new(NULL);
+
+ for (i = 0; sdram_bank_sizes[i]; i++) {
+ g_string_append_printf(s, "%" PRIi64 "%s",
+ sdram_bank_sizes[i] / MiB,
+ sdram_bank_sizes[i + 1] ? ", " : "");
+ }
+ error_setg(errp, "Invalid SDRAM banks");
+ error_append_hint(errp, "at most %d bank%s of %s MiB each supported\n",
+ nr_banks, nr_banks == 1 ? "" : "s", s->str);
+ error_append_hint(errp, "Possible valid RAM size: %" PRIi64 " MiB\n",
+ used_size ? used_size / MiB : sdram_bank_sizes[i - 1] / MiB);
+
+ g_string_free(s, true);
+ return false;
+ }
+ return true;
+}
+
+static void sdram_bank_map(Ppc4xxSdramBank *bank)
+{
+ trace_ppc4xx_sdram_map(bank->base, bank->size);
+ 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)
+{
+ trace_ppc4xx_sdram_unmap(bank->base, bank->size);
+ 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_bank_set_bcr(Ppc4xxSdramBank *bank, uint32_t bcr,
+ hwaddr base, hwaddr size, int enabled)
+{
+ if (memory_region_is_mapped(&bank->container)) {
+ sdram_bank_unmap(bank);
+ }
+ bank->bcr = bcr;
+ bank->base = base;
+ bank->size = size;
+ if (enabled && (bcr & 1)) {
+ sdram_bank_map(bank);
+ }
+}
+
+enum {
+ SDRAM0_CFGADDR = 0x010,
+ SDRAM0_CFGDATA = 0x011,
+};
+
+/*****************************************************************************/
+/* DDR SDRAM controller */
+#define SDRAM_DDR_BCR_MASK 0xFFDEE001
+
+static uint32_t sdram_ddr_bcr(hwaddr ram_base, hwaddr ram_size)
+{
+ uint32_t bcr;
+
+ switch (ram_size) {
+ case 4 * MiB:
+ bcr = 0;
+ break;
+ case 8 * MiB:
+ bcr = 0x20000;
+ break;
+ case 16 * MiB:
+ bcr = 0x40000;
+ break;
+ case 32 * MiB:
+ bcr = 0x60000;
+ break;
+ case 64 * MiB:
+ bcr = 0x80000;
+ break;
+ case 128 * MiB:
+ bcr = 0xA0000;
+ break;
+ case 256 * MiB:
+ bcr = 0xC0000;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: invalid RAM size 0x%" HWADDR_PRIx "\n", __func__,
+ ram_size);
+ return 0;
+ }
+ bcr |= ram_base & 0xFF800000;
+ bcr |= 1;
+
+ return bcr;
+}
+
+static inline hwaddr sdram_ddr_base(uint32_t bcr)
+{
+ return bcr & 0xFF800000;
+}
+
+static hwaddr sdram_ddr_size(uint32_t bcr)
+{
+ hwaddr size;
+ int sh;
+
+ sh = (bcr >> 17) & 0x7;
+ if (sh == 7) {
+ size = -1;
+ } else {
+ size = (4 * MiB) << sh;
+ }
+
+ return size;
+}
+
+static uint32_t sdram_ddr_dcr_read(void *opaque, int dcrn)
+{
+ Ppc4xxSdramDdrState *s = opaque;
+ uint32_t ret;
+
+ switch (dcrn) {
+ case SDRAM0_CFGADDR:
+ ret = s->addr;
+ break;
+ case SDRAM0_CFGDATA:
+ switch (s->addr) {
+ case 0x00: /* SDRAM_BESR0 */
+ ret = s->besr0;
+ break;
+ case 0x08: /* SDRAM_BESR1 */
+ ret = s->besr1;
+ break;
+ case 0x10: /* SDRAM_BEAR */
+ ret = s->bear;
+ break;
+ case 0x20: /* SDRAM_CFG */
+ ret = s->cfg;
+ break;
+ case 0x24: /* SDRAM_STATUS */
+ ret = s->status;
+ break;
+ case 0x30: /* SDRAM_RTR */
+ ret = s->rtr;
+ break;
+ case 0x34: /* SDRAM_PMIT */
+ ret = s->pmit;
+ break;
+ case 0x40: /* SDRAM_B0CR */
+ ret = s->bank[0].bcr;
+ break;
+ case 0x44: /* SDRAM_B1CR */
+ ret = s->bank[1].bcr;
+ break;
+ case 0x48: /* SDRAM_B2CR */
+ ret = s->bank[2].bcr;
+ break;
+ case 0x4C: /* SDRAM_B3CR */
+ ret = s->bank[3].bcr;
+ break;
+ case 0x80: /* SDRAM_TR */
+ ret = -1; /* ? */
+ break;
+ case 0x94: /* SDRAM_ECCCFG */
+ ret = s->ecccfg;
+ break;
+ case 0x98: /* SDRAM_ECCESR */
+ ret = s->eccesr;
+ break;
+ default: /* Error */
+ ret = -1;
+ break;
+ }
+ break;
+ default:
+ /* Avoid gcc warning */
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+static void sdram_ddr_dcr_write(void *opaque, int dcrn, uint32_t val)
+{
+ Ppc4xxSdramDdrState *s = opaque;
+ int i;
+
+ switch (dcrn) {
+ case SDRAM0_CFGADDR:
+ s->addr = val;
+ break;
+ case SDRAM0_CFGDATA:
+ switch (s->addr) {
+ case 0x00: /* SDRAM_BESR0 */
+ s->besr0 &= ~val;
+ break;
+ case 0x08: /* SDRAM_BESR1 */
+ s->besr1 &= ~val;
+ break;
+ case 0x10: /* SDRAM_BEAR */
+ s->bear = val;
+ break;
+ case 0x20: /* SDRAM_CFG */
+ val &= 0xFFE00000;
+ if (!(s->cfg & 0x80000000) && (val & 0x80000000)) {
+ trace_ppc4xx_sdram_enable("enable");
+ /* validate all RAM mappings */
+ for (i = 0; i < s->nbanks; i++) {
+ if (s->bank[i].size) {
+ sdram_bank_set_bcr(&s->bank[i], s->bank[i].bcr,
+ s->bank[i].base, s->bank[i].size,
+ 1);
+ }
+ }
+ s->status &= ~0x80000000;
+ } else if ((s->cfg & 0x80000000) && !(val & 0x80000000)) {
+ trace_ppc4xx_sdram_enable("disable");
+ /* invalidate all RAM mappings */
+ for (i = 0; i < s->nbanks; i++) {
+ if (s->bank[i].size) {
+ sdram_bank_set_bcr(&s->bank[i], s->bank[i].bcr,
+ s->bank[i].base, s->bank[i].size,
+ 0);
+ }
+ }
+ s->status |= 0x80000000;
+ }
+ if (!(s->cfg & 0x40000000) && (val & 0x40000000)) {
+ s->status |= 0x40000000;
+ } else if ((s->cfg & 0x40000000) && !(val & 0x40000000)) {
+ s->status &= ~0x40000000;
+ }
+ s->cfg = val;
+ break;
+ case 0x24: /* SDRAM_STATUS */
+ /* Read-only register */
+ break;
+ case 0x30: /* SDRAM_RTR */
+ s->rtr = val & 0x3FF80000;
+ break;
+ case 0x34: /* SDRAM_PMIT */
+ s->pmit = (val & 0xF8000000) | 0x07C00000;
+ break;
+ case 0x40: /* SDRAM_B0CR */
+ case 0x44: /* SDRAM_B1CR */
+ case 0x48: /* SDRAM_B2CR */
+ case 0x4C: /* SDRAM_B3CR */
+ i = (s->addr - 0x40) / 4;
+ val &= SDRAM_DDR_BCR_MASK;
+ if (s->bank[i].size) {
+ sdram_bank_set_bcr(&s->bank[i], val,
+ sdram_ddr_base(val), sdram_ddr_size(val),
+ s->cfg & 0x80000000);
+ }
+ break;
+ case 0x80: /* SDRAM_TR */
+ s->tr = val & 0x018FC01F;
+ break;
+ case 0x94: /* SDRAM_ECCCFG */
+ s->ecccfg = val & 0x00F00000;
+ break;
+ case 0x98: /* SDRAM_ECCESR */
+ val &= 0xFFF0F000;
+ if (s->eccesr == 0 && val != 0) {
+ qemu_irq_raise(s->irq);
+ } else if (s->eccesr != 0 && val == 0) {
+ qemu_irq_lower(s->irq);
+ }
+ s->eccesr = val;
+ break;
+ default: /* Error */
+ break;
+ }
+ break;
+ }
+}
+
+static void ppc4xx_sdram_ddr_reset(DeviceState *dev)
+{
+ Ppc4xxSdramDdrState *s = PPC4xx_SDRAM_DDR(dev);
+
+ s->addr = 0;
+ s->bear = 0;
+ s->besr0 = 0; /* No error */
+ s->besr1 = 0; /* No error */
+ s->cfg = 0;
+ s->ecccfg = 0; /* No ECC */
+ s->eccesr = 0; /* No error */
+ s->pmit = 0x07C00000;
+ s->rtr = 0x05F00000;
+ s->tr = 0x00854009;
+ /* We pre-initialize RAM banks */
+ s->status = 0;
+ s->cfg = 0x00800000;
+}
+
+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
+ };
+ int i;
+
+ 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;
+ }
+ if (!ppc4xx_sdram_banks(s->dram_mr, s->nbanks, s->bank,
+ valid_bank_sizes, errp)) {
+ return;
+ }
+ for (i = 0; i < s->nbanks; i++) {
+ if (s->bank[i].size) {
+ s->bank[i].bcr = sdram_ddr_bcr(s->bank[i].base, s->bank[i].size);
+ sdram_bank_set_bcr(&s->bank[i], s->bank[i].bcr,
+ s->bank[i].base, s->bank[i].size, 0);
+ } else {
+ sdram_bank_set_bcr(&s->bank[i], 0, 0, 0, 0);
+ }
+ trace_ppc4xx_sdram_init(sdram_ddr_base(s->bank[i].bcr),
+ sdram_ddr_size(s->bank[i].bcr),
+ s->bank[i].bcr);
+ }
+
+ 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);
+}
+
+/*****************************************************************************/
+/* DDR2 SDRAM controller */
+#define SDRAM_DDR2_BCR_MASK 0xffe0ffc1
+
+enum {
+ SDRAM_R0BAS = 0x40,
+ SDRAM_R1BAS,
+ SDRAM_R2BAS,
+ SDRAM_R3BAS,
+ SDRAM_CONF1HB = 0x45,
+ SDRAM_PLBADDULL = 0x4a,
+ SDRAM_CONF1LL = 0x4b,
+ SDRAM_CONFPATHB = 0x4f,
+ SDRAM_PLBADDUHB = 0x50,
+};
+
+static uint32_t sdram_ddr2_bcr(hwaddr ram_base, hwaddr ram_size)
+{
+ uint32_t bcr;
+
+ switch (ram_size) {
+ case 8 * MiB:
+ bcr = 0xffc0;
+ break;
+ case 16 * MiB:
+ bcr = 0xff80;
+ break;
+ case 32 * MiB:
+ bcr = 0xff00;
+ break;
+ case 64 * MiB:
+ bcr = 0xfe00;
+ break;
+ case 128 * MiB:
+ bcr = 0xfc00;
+ break;
+ case 256 * MiB:
+ bcr = 0xf800;
+ break;
+ case 512 * MiB:
+ bcr = 0xf000;
+ break;
+ case 1 * GiB:
+ bcr = 0xe000;
+ break;
+ case 2 * GiB:
+ bcr = 0xc000;
+ break;
+ case 4 * GiB:
+ bcr = 0x8000;
+ break;
+ default:
+ error_report("invalid RAM size " TARGET_FMT_plx, ram_size);
+ return 0;
+ }
+ bcr |= ram_base >> 2 & 0xffe00000;
+ bcr |= 1;
+
+ return bcr;
+}
+
+static inline hwaddr sdram_ddr2_base(uint32_t bcr)
+{
+ return (bcr & 0xffe00000) << 2;
+}
+
+static hwaddr sdram_ddr2_size(uint32_t bcr)
+{
+ hwaddr size;
+ int sh;
+
+ sh = 1024 - ((bcr >> 6) & 0x3ff);
+ size = 8 * MiB * sh;
+
+ return size;
+}
+
+static uint32_t sdram_ddr2_dcr_read(void *opaque, int dcrn)
+{
+ Ppc4xxSdramDdr2State *s = opaque;
+ uint32_t ret = 0;
+
+ switch (dcrn) {
+ case SDRAM_R0BAS:
+ case SDRAM_R1BAS:
+ case SDRAM_R2BAS:
+ case SDRAM_R3BAS:
+ if (s->bank[dcrn - SDRAM_R0BAS].size) {
+ ret = sdram_ddr2_bcr(s->bank[dcrn - SDRAM_R0BAS].base,
+ s->bank[dcrn - SDRAM_R0BAS].size);
+ }
+ break;
+ case SDRAM_CONF1HB:
+ case SDRAM_CONF1LL:
+ case SDRAM_CONFPATHB:
+ case SDRAM_PLBADDULL:
+ case SDRAM_PLBADDUHB:
+ break;
+ case SDRAM0_CFGADDR:
+ ret = s->addr;
+ break;
+ case SDRAM0_CFGDATA:
+ switch (s->addr) {
+ case 0x14: /* SDRAM_MCSTAT (405EX) */
+ case 0x1F:
+ ret = 0x80000000;
+ break;
+ case 0x21: /* SDRAM_MCOPT2 */
+ ret = s->mcopt2;
+ break;
+ case 0x40: /* SDRAM_MB0CF */
+ ret = 0x00008001;
+ break;
+ case 0x7A: /* SDRAM_DLCR */
+ ret = 0x02000000;
+ break;
+ case 0xE1: /* SDR0_DDR0 */
+ ret = SDR0_DDR0_DDRM_ENCODE(1) | SDR0_DDR0_DDRM_DDR1;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+#define SDRAM_DDR2_MCOPT2_DCEN BIT(27)
+
+static void sdram_ddr2_dcr_write(void *opaque, int dcrn, uint32_t val)
+{
+ Ppc4xxSdramDdr2State *s = opaque;
+ int i;
+
+ switch (dcrn) {
+ case SDRAM_R0BAS:
+ case SDRAM_R1BAS:
+ case SDRAM_R2BAS:
+ case SDRAM_R3BAS:
+ case SDRAM_CONF1HB:
+ case SDRAM_CONF1LL:
+ case SDRAM_CONFPATHB:
+ case SDRAM_PLBADDULL:
+ case SDRAM_PLBADDUHB:
+ break;
+ case SDRAM0_CFGADDR:
+ s->addr = val;
+ break;
+ case SDRAM0_CFGDATA:
+ switch (s->addr) {
+ case 0x00: /* B0CR */
+ break;
+ case 0x21: /* SDRAM_MCOPT2 */
+ if (!(s->mcopt2 & SDRAM_DDR2_MCOPT2_DCEN) &&
+ (val & SDRAM_DDR2_MCOPT2_DCEN)) {
+ trace_ppc4xx_sdram_enable("enable");
+ /* validate all RAM mappings */
+ for (i = 0; i < s->nbanks; i++) {
+ if (s->bank[i].size) {
+ sdram_bank_set_bcr(&s->bank[i], s->bank[i].bcr,
+ s->bank[i].base, s->bank[i].size,
+ 1);
+ }
+ }
+ s->mcopt2 |= SDRAM_DDR2_MCOPT2_DCEN;
+ } else if ((s->mcopt2 & SDRAM_DDR2_MCOPT2_DCEN) &&
+ !(val & SDRAM_DDR2_MCOPT2_DCEN)) {
+ trace_ppc4xx_sdram_enable("disable");
+ /* invalidate all RAM mappings */
+ for (i = 0; i < s->nbanks; i++) {
+ if (s->bank[i].size) {
+ sdram_bank_set_bcr(&s->bank[i], s->bank[i].bcr,
+ s->bank[i].base, s->bank[i].size,
+ 0);
+ }
+ }
+ s->mcopt2 &= ~SDRAM_DDR2_MCOPT2_DCEN;
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void ppc4xx_sdram_ddr2_reset(DeviceState *dev)
+{
+ Ppc4xxSdramDdr2State *s = PPC4xx_SDRAM_DDR2(dev);
+
+ s->addr = 0;
+ s->mcopt2 = 0;
+}
+
+static void ppc4xx_sdram_ddr2_realize(DeviceState *dev, Error **errp)
+{
+ 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
+ };
+ int i;
+
+ 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;
+ }
+ if (!ppc4xx_sdram_banks(s->dram_mr, s->nbanks, s->bank,
+ valid_bank_sizes, errp)) {
+ return;
+ }
+ for (i = 0; i < s->nbanks; i++) {
+ if (s->bank[i].size) {
+ s->bank[i].bcr = sdram_ddr2_bcr(s->bank[i].base, s->bank[i].size);
+ s->bank[i].bcr &= SDRAM_DDR2_BCR_MASK;
+ sdram_bank_set_bcr(&s->bank[i], s->bank[i].bcr,
+ s->bank[i].base, s->bank[i].size, 0);
+ } else {
+ sdram_bank_set_bcr(&s->bank[i], 0, 0, 0, 0);
+ }
+ trace_ppc4xx_sdram_init(sdram_ddr2_base(s->bank[i].bcr),
+ sdram_ddr2_size(s->bank[i].bcr),
+ s->bank[i].bcr);
+ }
+
+ ppc4xx_dcr_register(dcr, SDRAM0_CFGADDR,
+ s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write);
+ ppc4xx_dcr_register(dcr, SDRAM0_CFGDATA,
+ s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write);
+
+ ppc4xx_dcr_register(dcr, SDRAM_R0BAS,
+ s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write);
+ ppc4xx_dcr_register(dcr, SDRAM_R1BAS,
+ s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write);
+ ppc4xx_dcr_register(dcr, SDRAM_R2BAS,
+ s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write);
+ ppc4xx_dcr_register(dcr, SDRAM_R3BAS,
+ s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write);
+ ppc4xx_dcr_register(dcr, SDRAM_CONF1HB,
+ s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write);
+ ppc4xx_dcr_register(dcr, SDRAM_PLBADDULL,
+ s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write);
+ ppc4xx_dcr_register(dcr, SDRAM_CONF1LL,
+ s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write);
+ ppc4xx_dcr_register(dcr, SDRAM_CONFPATHB,
+ s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write);
+ ppc4xx_dcr_register(dcr, SDRAM_PLBADDUHB,
+ s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write);
+}
+
+static Property ppc4xx_sdram_ddr2_props[] = {
+ DEFINE_PROP_LINK("dram", Ppc4xxSdramDdr2State, dram_mr, TYPE_MEMORY_REGION,
+ MemoryRegion *),
+ DEFINE_PROP_UINT32("nbanks", Ppc4xxSdramDdr2State, nbanks, 4),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ppc4xx_sdram_ddr2_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ dc->realize = ppc4xx_sdram_ddr2_realize;
+ dc->reset = ppc4xx_sdram_ddr2_reset;
+ /* Reason: only works as function of a ppc4xx SoC */
+ dc->user_creatable = false;
+ device_class_set_props(dc, ppc4xx_sdram_ddr2_props);
+}
+
+void ppc4xx_sdram_ddr2_enable(Ppc4xxSdramDdr2State *s)
+{
+ sdram_ddr2_dcr_write(s, SDRAM0_CFGADDR, 0x21);
+ sdram_ddr2_dcr_write(s, SDRAM0_CFGDATA, 0x08000000);
+}
+
+static const TypeInfo ppc4xx_sdram_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_SDRAM_DDR2,
+ .parent = TYPE_PPC4xx_DCR_DEVICE,
+ .instance_size = sizeof(Ppc4xxSdramDdr2State),
+ .class_init = ppc4xx_sdram_ddr2_class_init,
+ }
+};
+
+DEFINE_TYPES(ppc4xx_sdram_types)
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 891206e..925ff52 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -490,6 +490,7 @@ static target_ulong h_cede(PowerPCCPU *cpu, SpaprMachineState *spapr,
env->msr |= (1ULL << MSR_EE);
hreg_compute_hflags(env);
+ ppc_maybe_interrupt(env);
if (spapr_cpu->prod) {
spapr_cpu->prod = false;
@@ -500,6 +501,7 @@ static target_ulong h_cede(PowerPCCPU *cpu, SpaprMachineState *spapr,
cs->halted = 1;
cs->exception_index = EXCP_HLT;
cs->exit_request = 1;
+ ppc_maybe_interrupt(env);
}
return H_SUCCESS;
@@ -521,6 +523,7 @@ static target_ulong h_confer_self(PowerPCCPU *cpu)
cs->halted = 1;
cs->exception_index = EXCP_HALTED;
cs->exit_request = 1;
+ ppc_maybe_interrupt(&cpu->env);
return H_SUCCESS;
}
@@ -633,6 +636,7 @@ static target_ulong h_prod(PowerPCCPU *cpu, SpaprMachineState *spapr,
spapr_cpu = spapr_cpu_state(tcpu);
spapr_cpu->prod = true;
cs->halted = 0;
+ ppc_maybe_interrupt(&cpu->env);
qemu_cpu_kick(cs);
return H_SUCCESS;
@@ -1669,6 +1673,7 @@ static target_ulong h_enter_nested(PowerPCCPU *cpu,
spapr_cpu->in_nested = true;
hreg_compute_hflags(env);
+ ppc_maybe_interrupt(env);
tlb_flush(cs);
env->reserve_addr = -1; /* Reset the reservation */
@@ -1810,6 +1815,7 @@ out_restore_l1:
spapr_cpu->in_nested = false;
hreg_compute_hflags(env);
+ ppc_maybe_interrupt(env);
tlb_flush(cs);
env->reserve_addr = -1; /* Reset the reservation */
diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c
index d58b65e..3f664ea 100644
--- a/hw/ppc/spapr_rtas.c
+++ b/hw/ppc/spapr_rtas.c
@@ -214,9 +214,9 @@ static void rtas_stop_self(PowerPCCPU *cpu, SpaprMachineState *spapr,
* guest.
* For the same reason, set PSSCR_EC.
*/
- ppc_store_lpcr(cpu, env->spr[SPR_LPCR] & ~pcc->lpcr_pm);
env->spr[SPR_PSSCR] |= PSSCR_EC;
cs->halted = 1;
+ ppc_store_lpcr(cpu, env->spr[SPR_LPCR] & ~pcc->lpcr_pm);
kvmppc_set_reg_ppc_online(cpu, 0);
qemu_cpu_kick(cs);
}
diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events
index a07d5ac..f670e89 100644
--- a/hw/ppc/trace-events
+++ b/hw/ppc/trace-events
@@ -127,7 +127,7 @@ ppc40x_set_tb_clk(uint32_t value) "new frequency %" PRIu32
ppc40x_timers_init(uint32_t value) "frequency %" PRIu32
ppc_irq_set(void *env, uint32_t pin, uint32_t level) "env [%p] pin %d level %d"
-ppc_irq_set_exit(void *env, uint32_t n_IRQ, uint32_t level, uint32_t pending, uint32_t request) "env [%p] n_IRQ %d level %d => pending 0x%08" PRIx32 " req 0x%08" PRIx32
+ppc_irq_set_exit(void *env, uint32_t irq, uint32_t level, uint32_t pending, uint32_t request) "env [%p] irq 0x%05" PRIx32 " level %d => pending 0x%08" PRIx32 " req 0x%08" PRIx32
ppc_irq_set_state(const char *name, uint32_t level) "\"%s\" level %d"
ppc_irq_reset(const char *name) "%s"
ppc_irq_cpu(const char *action) "%s"
@@ -179,3 +179,4 @@ ppc405ep_clocks_setup(const char *trace) "%s"
ppc4xx_sdram_enable(const char *trace) "%s SDRAM controller"
ppc4xx_sdram_unmap(uint64_t addr, uint64_t size) "Unmap RAM area 0x%" PRIx64 " size 0x%" PRIx64
ppc4xx_sdram_map(uint64_t addr, uint64_t size) "Map RAM area 0x%" PRIx64 " size 0x%" PRIx64
+ppc4xx_sdram_init(uint64_t base, uint64_t size, uint32_t bcr) "Init RAM area 0x%" PRIx64 " size 0x%" PRIx64 " bcr 0x%x"
diff --git a/hw/sd/sdhci-internal.h b/hw/sd/sdhci-internal.h
index e8c753d..964570f 100644
--- a/hw/sd/sdhci-internal.h
+++ b/hw/sd/sdhci-internal.h
@@ -288,26 +288,6 @@ enum {
extern const VMStateDescription sdhci_vmstate;
-
-#define ESDHC_MIX_CTRL 0x48
-
-#define ESDHC_VENDOR_SPEC 0xc0
-#define ESDHC_IMX_FRC_SDCLK_ON (1 << 8)
-
-#define ESDHC_DLL_CTRL 0x60
-
-#define ESDHC_TUNING_CTRL 0xcc
-#define ESDHC_TUNE_CTRL_STATUS 0x68
-#define ESDHC_WTMK_LVL 0x44
-
-/* Undocumented register used by guests working around erratum ERR004536 */
-#define ESDHC_UNDOCUMENTED_REG27 0x6c
-
-#define ESDHC_CTRL_4BITBUS (0x1 << 1)
-#define ESDHC_CTRL_8BITBUS (0x2 << 1)
-
-#define ESDHC_PRNSTS_SDSTB (1 << 3)
-
/*
* Default SD/MMC host controller features information, which will be
* presented in CAPABILITIES register of generic SD host controller at reset.
diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c
index 0e5e9889..306070c 100644
--- a/hw/sd/sdhci.c
+++ b/hw/sd/sdhci.c
@@ -1577,6 +1577,25 @@ static const TypeInfo sdhci_bus_info = {
/* --- qdev i.MX eSDHC --- */
+#define USDHC_MIX_CTRL 0x48
+
+#define USDHC_VENDOR_SPEC 0xc0
+#define USDHC_IMX_FRC_SDCLK_ON (1 << 8)
+
+#define USDHC_DLL_CTRL 0x60
+
+#define USDHC_TUNING_CTRL 0xcc
+#define USDHC_TUNE_CTRL_STATUS 0x68
+#define USDHC_WTMK_LVL 0x44
+
+/* Undocumented register used by guests working around erratum ERR004536 */
+#define USDHC_UNDOCUMENTED_REG27 0x6c
+
+#define USDHC_CTRL_4BITBUS (0x1 << 1)
+#define USDHC_CTRL_8BITBUS (0x2 << 1)
+
+#define USDHC_PRNSTS_SDSTB (1 << 3)
+
static uint64_t usdhc_read(void *opaque, hwaddr offset, unsigned size)
{
SDHCIState *s = SYSBUS_SDHCI(opaque);
@@ -1596,11 +1615,11 @@ static uint64_t usdhc_read(void *opaque, hwaddr offset, unsigned size)
hostctl1 = SDHC_DMA_TYPE(s->hostctl1) << (8 - 3);
if (s->hostctl1 & SDHC_CTRL_8BITBUS) {
- hostctl1 |= ESDHC_CTRL_8BITBUS;
+ hostctl1 |= USDHC_CTRL_8BITBUS;
}
if (s->hostctl1 & SDHC_CTRL_4BITBUS) {
- hostctl1 |= ESDHC_CTRL_4BITBUS;
+ hostctl1 |= USDHC_CTRL_4BITBUS;
}
ret = hostctl1;
@@ -1611,21 +1630,21 @@ static uint64_t usdhc_read(void *opaque, hwaddr offset, unsigned size)
case SDHC_PRNSTS:
/* Add SDSTB (SD Clock Stable) bit to PRNSTS */
- ret = sdhci_read(opaque, offset, size) & ~ESDHC_PRNSTS_SDSTB;
+ ret = sdhci_read(opaque, offset, size) & ~USDHC_PRNSTS_SDSTB;
if (s->clkcon & SDHC_CLOCK_INT_STABLE) {
- ret |= ESDHC_PRNSTS_SDSTB;
+ ret |= USDHC_PRNSTS_SDSTB;
}
break;
- case ESDHC_VENDOR_SPEC:
+ case USDHC_VENDOR_SPEC:
ret = s->vendor_spec;
break;
- case ESDHC_DLL_CTRL:
- case ESDHC_TUNE_CTRL_STATUS:
- case ESDHC_UNDOCUMENTED_REG27:
- case ESDHC_TUNING_CTRL:
- case ESDHC_MIX_CTRL:
- case ESDHC_WTMK_LVL:
+ case USDHC_DLL_CTRL:
+ case USDHC_TUNE_CTRL_STATUS:
+ case USDHC_UNDOCUMENTED_REG27:
+ case USDHC_TUNING_CTRL:
+ case USDHC_MIX_CTRL:
+ case USDHC_WTMK_LVL:
ret = 0;
break;
}
@@ -1641,18 +1660,18 @@ usdhc_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
uint32_t value = (uint32_t)val;
switch (offset) {
- case ESDHC_DLL_CTRL:
- case ESDHC_TUNE_CTRL_STATUS:
- case ESDHC_UNDOCUMENTED_REG27:
- case ESDHC_TUNING_CTRL:
- case ESDHC_WTMK_LVL:
+ case USDHC_DLL_CTRL:
+ case USDHC_TUNE_CTRL_STATUS:
+ case USDHC_UNDOCUMENTED_REG27:
+ case USDHC_TUNING_CTRL:
+ case USDHC_WTMK_LVL:
break;
- case ESDHC_VENDOR_SPEC:
+ case USDHC_VENDOR_SPEC:
s->vendor_spec = value;
switch (s->vendor) {
case SDHCI_VENDOR_IMX:
- if (value & ESDHC_IMX_FRC_SDCLK_ON) {
+ if (value & USDHC_IMX_FRC_SDCLK_ON) {
s->prnsts &= ~SDHC_IMX_CLOCK_GATE_OFF;
} else {
s->prnsts |= SDHC_IMX_CLOCK_GATE_OFF;
@@ -1721,12 +1740,12 @@ usdhc_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
* Second, split "Data Transfer Width" from bits 2 and 1 in to
* bits 5 and 1
*/
- if (value & ESDHC_CTRL_8BITBUS) {
+ if (value & USDHC_CTRL_8BITBUS) {
hostctl1 |= SDHC_CTRL_8BITBUS;
}
- if (value & ESDHC_CTRL_4BITBUS) {
- hostctl1 |= ESDHC_CTRL_4BITBUS;
+ if (value & USDHC_CTRL_4BITBUS) {
+ hostctl1 |= USDHC_CTRL_4BITBUS;
}
/*
@@ -1749,7 +1768,7 @@ usdhc_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
sdhci_write(opaque, offset, value, size);
break;
- case ESDHC_MIX_CTRL:
+ case USDHC_MIX_CTRL:
/*
* So, when SD/MMC stack in Linux tries to write to "Transfer
* Mode Register", ESDHC i.MX quirk code will translate it