All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v2 0/3] Sam460ex emulation
@ 2018-02-15 21:27 BALATON Zoltan
  2018-02-15 21:27 ` [Qemu-devel] [PATCH v2 1/3] ppc4xx: Add device models found in PPC440 core SoCs BALATON Zoltan
                   ` (4 more replies)
  0 siblings, 5 replies; 16+ messages in thread
From: BALATON Zoltan @ 2018-02-15 21:27 UTC (permalink / raw)
  To: qemu-devel, qemu-ppc; +Cc: Alexander Graf, David Gibson, Francois Revol

Remaining patches for Sam460ex emulation. The original cover letter
with more details is here:

http://lists.nongnu.org/archive/html/qemu-ppc/2017-08/msg00112.html

We'll need to also add binaries for firmware (customised u-boot
version) and dtb but I'm not sure how to submit those.

Current status for OSes I've tried:

- AROS boots (after I've fixed some bugs in it which are now upstream
  so the nightly iso should work) but keyboard doesn't work (could be
  a bug in AROS's HID driver) and time is going slow (this can be seen
  in time prefs). This may be a QEMU bug and possibly causes the hang
  seen in other OSes but I don't know what causes it or how to fix it.
  Maybe related to some internal timing registers of the SoC because
  setting multipliers to real values causes U-Boot to become slow.
  Anyone with more knowledge of this hardware has any idea?

- Linux: kernel boots but hangs during user space (again could be the
  above timing problem or maybe missing emac network interface
  emulation but I don't really know).

- AmigaOS 4 seems to boot but display is not working so not usable
  (either related to timing problem or could be SM502 emulation).

- MorphOS does not boot (it seems to either deliberately do stuff to
  prevent it from running on QEMU or it has bugs but developers are
  not communicative about it)

Regards,
BALATON Zoltan

BALATON Zoltan (3):
  ppc4xx: Add device models found in PPC440 core SoCs
  ppc440: Add emulation of plb-pcix controller found in some 440 SoCs
  ppc: Add aCube Sam460ex board

 default-configs/ppc-softmmu.mak    |    2 +
 default-configs/ppcemb-softmmu.mak |    1 +
 hw/ppc/Makefile.objs               |    3 +-
 hw/ppc/ppc440.h                    |   26 +
 hw/ppc/ppc440_pcix.c               |  528 ++++++++++++++++
 hw/ppc/ppc440_uc.c                 | 1159 ++++++++++++++++++++++++++++++++++++
 hw/ppc/sam460ex.c                  |  603 +++++++++++++++++++
 hw/ppc/trace-events                |    8 +
 include/hw/pci/pcie_host.h         |    2 +-
 9 files changed, 2330 insertions(+), 2 deletions(-)
 create mode 100644 hw/ppc/ppc440.h
 create mode 100644 hw/ppc/ppc440_pcix.c
 create mode 100644 hw/ppc/ppc440_uc.c
 create mode 100644 hw/ppc/sam460ex.c

-- 
2.7.6

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [Qemu-devel] [PATCH v2 2/3] ppc440: Add emulation of plb-pcix controller found in some 440 SoCs
  2018-02-15 21:27 [Qemu-devel] [PATCH v2 0/3] Sam460ex emulation BALATON Zoltan
  2018-02-15 21:27 ` [Qemu-devel] [PATCH v2 1/3] ppc4xx: Add device models found in PPC440 core SoCs BALATON Zoltan
  2018-02-15 21:27 ` [Qemu-devel] [PATCH v2 3/3] ppc: Add aCube Sam460ex board BALATON Zoltan
@ 2018-02-15 21:27 ` BALATON Zoltan
  2018-02-16  6:50 ` [Qemu-devel] [Qemu-ppc] [PATCH v2 0/3] Sam460ex emulation Thomas Huth
  2018-06-21 21:15 ` [Qemu-devel] [v2,0/3] " Guenter Roeck
  4 siblings, 0 replies; 16+ messages in thread
From: BALATON Zoltan @ 2018-02-15 21:27 UTC (permalink / raw)
  To: qemu-devel, qemu-ppc; +Cc: Alexander Graf, David Gibson, Francois Revol

This is the PCIX controller found in newer 440 core SoCs e.g. the
AMMC 460EX. The device tree refers to this as plb-pcix compared to
the plb-pci controller in older 440 SoCs.

Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
---

v2:
- Replace debug printfs with trace functions
- Fix access of low address registers

 hw/ppc/Makefile.objs |   2 +-
 hw/ppc/ppc440_pcix.c | 528 +++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/ppc/trace-events  |   8 +
 3 files changed, 537 insertions(+), 1 deletion(-)
 create mode 100644 hw/ppc/ppc440_pcix.c

diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs
index ad1928c..bddc742 100644
--- a/hw/ppc/Makefile.objs
+++ b/hw/ppc/Makefile.objs
@@ -13,7 +13,7 @@ endif
 obj-$(CONFIG_PSERIES) += spapr_rtas_ddw.o
 # PowerPC 4xx boards
 obj-y += ppc4xx_devs.o ppc405_uc.o
-obj-$(CONFIG_PPC4XX) += ppc4xx_pci.o ppc405_boards.o ppc440_bamboo.o
+obj-$(CONFIG_PPC4XX) += ppc4xx_pci.o ppc405_boards.o ppc440_bamboo.o ppc440_pcix.o
 # PReP
 obj-$(CONFIG_PREP) += prep.o
 obj-$(CONFIG_PREP) += prep_systemio.o
diff --git a/hw/ppc/ppc440_pcix.c b/hw/ppc/ppc440_pcix.c
new file mode 100644
index 0000000..ab2626a
--- /dev/null
+++ b/hw/ppc/ppc440_pcix.c
@@ -0,0 +1,528 @@
+/*
+ * Emulation of the ibm,plb-pcix PCI controller
+ * This is found in some 440 SoCs e.g. the 460EX.
+ *
+ * Copyright (c) 2016-2018 BALATON Zoltan
+ *
+ * Derived from ppc4xx_pci.c and pci-host/ppce500.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "hw/hw.h"
+#include "hw/ppc/ppc.h"
+#include "hw/ppc/ppc4xx.h"
+#include "hw/pci/pci.h"
+#include "hw/pci/pci_host.h"
+#include "exec/address-spaces.h"
+#include "trace.h"
+
+struct PLBOutMap {
+    uint64_t la;
+    uint64_t pcia;
+    uint32_t sa;
+    MemoryRegion mr;
+};
+
+struct PLBInMap {
+    uint64_t sa;
+    uint64_t la;
+    MemoryRegion mr;
+};
+
+#define TYPE_PPC440_PCIX_HOST_BRIDGE "ppc440-pcix-host"
+#define PPC440_PCIX_HOST_BRIDGE(obj) \
+    OBJECT_CHECK(PPC440PCIXState, (obj), TYPE_PPC440_PCIX_HOST_BRIDGE)
+
+#define PPC440_PCIX_NR_POMS 3
+#define PPC440_PCIX_NR_PIMS 3
+
+typedef struct PPC440PCIXState {
+    PCIHostState parent_obj;
+
+    PCIDevice *dev;
+    struct PLBOutMap pom[PPC440_PCIX_NR_POMS];
+    struct PLBInMap pim[PPC440_PCIX_NR_PIMS];
+    uint32_t sts;
+    qemu_irq irq[PCI_NUM_PINS];
+    AddressSpace bm_as;
+    MemoryRegion bm;
+
+    MemoryRegion container;
+    MemoryRegion iomem;
+    MemoryRegion busmem;
+} PPC440PCIXState;
+
+#define PPC440_REG_BASE     0x80000
+#define PPC440_REG_SIZE     0xff
+
+#define PCIC0_CFGADDR       0x0
+#define PCIC0_CFGDATA       0x4
+
+#define PCIX0_POM0LAL       0x68
+#define PCIX0_POM0LAH       0x6c
+#define PCIX0_POM0SA        0x70
+#define PCIX0_POM0PCIAL     0x74
+#define PCIX0_POM0PCIAH     0x78
+#define PCIX0_POM1LAL       0x7c
+#define PCIX0_POM1LAH       0x80
+#define PCIX0_POM1SA        0x84
+#define PCIX0_POM1PCIAL     0x88
+#define PCIX0_POM1PCIAH     0x8c
+#define PCIX0_POM2SA        0x90
+
+#define PCIX0_PIM0SAL       0x98
+#define PCIX0_PIM0LAL       0x9c
+#define PCIX0_PIM0LAH       0xa0
+#define PCIX0_PIM1SA        0xa4
+#define PCIX0_PIM1LAL       0xa8
+#define PCIX0_PIM1LAH       0xac
+#define PCIX0_PIM2SAL       0xb0
+#define PCIX0_PIM2LAL       0xb4
+#define PCIX0_PIM2LAH       0xb8
+#define PCIX0_PIM0SAH       0xf8
+#define PCIX0_PIM2SAH       0xfc
+
+#define PCIX0_STS           0xe0
+
+#define PCI_ALL_SIZE        (PPC440_REG_BASE + PPC440_REG_SIZE)
+
+static void ppc440_pcix_clear_region(MemoryRegion *parent,
+                                     MemoryRegion *mem)
+{
+    if (memory_region_is_mapped(mem)) {
+        memory_region_del_subregion(parent, mem);
+        object_unparent(OBJECT(mem));
+    }
+}
+
+/* DMA mapping */
+static void ppc440_pcix_update_pim(PPC440PCIXState *s, int idx)
+{
+    MemoryRegion *mem = &s->pim[idx].mr;
+    char *name;
+    uint64_t size;
+
+    /* Before we modify anything, unmap and destroy the region */
+    ppc440_pcix_clear_region(&s->bm, mem);
+
+    if (!(s->pim[idx].sa & 1)) {
+        /* Not enabled, nothing to do */
+        return;
+    }
+
+    name = g_strdup_printf("PCI Inbound Window %d", idx);
+    size = ~(s->pim[idx].sa & ~7ULL) + 1;
+    memory_region_init_alias(mem, OBJECT(s), name, get_system_memory(),
+                             s->pim[idx].la, size);
+    memory_region_add_subregion_overlap(&s->bm, 0, mem, -1);
+    g_free(name);
+
+    trace_ppc440_pcix_update_pim(idx, size, s->pim[idx].la);
+}
+
+/* BAR mapping */
+static void ppc440_pcix_update_pom(PPC440PCIXState *s, int idx)
+{
+    MemoryRegion *mem = &s->pom[idx].mr;
+    MemoryRegion *address_space_mem = get_system_memory();
+    char *name;
+    uint32_t size;
+
+    /* Before we modify anything, unmap and destroy the region */
+    ppc440_pcix_clear_region(address_space_mem, mem);
+
+    if (!(s->pom[idx].sa & 1)) {
+        /* Not enabled, nothing to do */
+        return;
+    }
+
+    name = g_strdup_printf("PCI Outbound Window %d", idx);
+    size = ~(s->pom[idx].sa & 0xfffffffe) + 1;
+    if (!size) {
+        size = 0xffffffff;
+    }
+    memory_region_init_alias(mem, OBJECT(s), name, &s->busmem,
+                             s->pom[idx].pcia, size);
+    memory_region_add_subregion(address_space_mem, s->pom[idx].la, mem);
+    g_free(name);
+
+    trace_ppc440_pcix_update_pom(idx, size, s->pom[idx].la, s->pom[idx].pcia);
+}
+
+static void ppc440_pcix_reg_write4(void *opaque, hwaddr addr,
+                                   uint64_t val, unsigned size)
+{
+    struct PPC440PCIXState *s = opaque;
+
+    trace_ppc440_pcix_reg_read(addr, val);
+    switch (addr) {
+    case PCI_VENDOR_ID ... PCI_MAX_LAT:
+        stl_le_p(s->dev->config + addr, val);
+        break;
+
+    case PCIX0_POM0LAL:
+        s->pom[0].la &= 0xffffffff00000000ULL;
+        s->pom[0].la |= val;
+        ppc440_pcix_update_pom(s, 0);
+        break;
+    case PCIX0_POM0LAH:
+        s->pom[0].la &= 0xffffffffULL;
+        s->pom[0].la |= val << 32;
+        ppc440_pcix_update_pom(s, 0);
+        break;
+    case PCIX0_POM0SA:
+        s->pom[0].sa = val;
+        ppc440_pcix_update_pom(s, 0);
+        break;
+    case PCIX0_POM0PCIAL:
+        s->pom[0].pcia &= 0xffffffff00000000ULL;
+        s->pom[0].pcia |= val;
+        ppc440_pcix_update_pom(s, 0);
+        break;
+    case PCIX0_POM0PCIAH:
+        s->pom[0].pcia &= 0xffffffffULL;
+        s->pom[0].pcia |= val << 32;
+        ppc440_pcix_update_pom(s, 0);
+        break;
+    case PCIX0_POM1LAL:
+        s->pom[1].la &= 0xffffffff00000000ULL;
+        s->pom[1].la |= val;
+        ppc440_pcix_update_pom(s, 1);
+        break;
+    case PCIX0_POM1LAH:
+        s->pom[1].la &= 0xffffffffULL;
+        s->pom[1].la |= val << 32;
+        ppc440_pcix_update_pom(s, 1);
+        break;
+    case PCIX0_POM1SA:
+        s->pom[1].sa = val;
+        ppc440_pcix_update_pom(s, 1);
+        break;
+    case PCIX0_POM1PCIAL:
+        s->pom[1].pcia &= 0xffffffff00000000ULL;
+        s->pom[1].pcia |= val;
+        ppc440_pcix_update_pom(s, 1);
+        break;
+    case PCIX0_POM1PCIAH:
+        s->pom[1].pcia &= 0xffffffffULL;
+        s->pom[1].pcia |= val << 32;
+        ppc440_pcix_update_pom(s, 1);
+        break;
+    case PCIX0_POM2SA:
+        s->pom[2].sa = val;
+        break;
+
+    case PCIX0_PIM0SAL:
+        s->pim[0].sa &= 0xffffffff00000000ULL;
+        s->pim[0].sa |= val;
+        ppc440_pcix_update_pim(s, 0);
+        break;
+    case PCIX0_PIM0LAL:
+        s->pim[0].la &= 0xffffffff00000000ULL;
+        s->pim[0].la |= val;
+        ppc440_pcix_update_pim(s, 0);
+        break;
+    case PCIX0_PIM0LAH:
+        s->pim[0].la &= 0xffffffffULL;
+        s->pim[0].la |= val << 32;
+        ppc440_pcix_update_pim(s, 0);
+        break;
+    case PCIX0_PIM1SA:
+        s->pim[1].sa = val;
+        ppc440_pcix_update_pim(s, 1);
+        break;
+    case PCIX0_PIM1LAL:
+        s->pim[1].la &= 0xffffffff00000000ULL;
+        s->pim[1].la |= val;
+        ppc440_pcix_update_pim(s, 1);
+        break;
+    case PCIX0_PIM1LAH:
+        s->pim[1].la &= 0xffffffffULL;
+        s->pim[1].la |= val << 32;
+        ppc440_pcix_update_pim(s, 1);
+        break;
+    case PCIX0_PIM2SAL:
+        s->pim[2].sa &= 0xffffffff00000000ULL;
+        s->pim[2].sa = val;
+        ppc440_pcix_update_pim(s, 2);
+        break;
+    case PCIX0_PIM2LAL:
+        s->pim[2].la &= 0xffffffff00000000ULL;
+        s->pim[2].la |= val;
+        ppc440_pcix_update_pim(s, 2);
+        break;
+    case PCIX0_PIM2LAH:
+        s->pim[2].la &= 0xffffffffULL;
+        s->pim[2].la |= val << 32;
+        ppc440_pcix_update_pim(s, 2);
+        break;
+
+    case PCIX0_STS:
+        s->sts = val;
+        break;
+
+    case PCIX0_PIM0SAH:
+        s->pim[0].sa &= 0xffffffffULL;
+        s->pim[0].sa |= val << 32;
+        ppc440_pcix_update_pim(s, 0);
+        break;
+    case PCIX0_PIM2SAH:
+        s->pim[2].sa &= 0xffffffffULL;
+        s->pim[2].sa |= val << 32;
+        ppc440_pcix_update_pim(s, 2);
+        break;
+
+    default:
+        error_report("%s: unhandled PCI internal register 0x%lx", __func__,
+                     (unsigned long)addr);
+        break;
+    }
+}
+
+static uint64_t ppc440_pcix_reg_read4(void *opaque, hwaddr addr,
+                                     unsigned size)
+{
+    struct PPC440PCIXState *s = opaque;
+    uint32_t val;
+
+    switch (addr) {
+    case PCI_VENDOR_ID ... PCI_MAX_LAT:
+        val = ldl_le_p(s->dev->config + addr);
+        break;
+
+    case PCIX0_POM0LAL:
+        val = s->pom[0].la;
+        break;
+    case PCIX0_POM0LAH:
+        val = s->pom[0].la >> 32;
+        break;
+    case PCIX0_POM0SA:
+        val = s->pom[0].sa;
+        break;
+    case PCIX0_POM0PCIAL:
+        val = s->pom[0].pcia;
+        break;
+    case PCIX0_POM0PCIAH:
+        val = s->pom[0].pcia >> 32;
+        break;
+    case PCIX0_POM1LAL:
+        val = s->pom[1].la;
+        break;
+    case PCIX0_POM1LAH:
+        val = s->pom[1].la >> 32;
+        break;
+    case PCIX0_POM1SA:
+        val = s->pom[1].sa;
+        break;
+    case PCIX0_POM1PCIAL:
+        val = s->pom[1].pcia;
+        break;
+    case PCIX0_POM1PCIAH:
+        val = s->pom[1].pcia >> 32;
+        break;
+    case PCIX0_POM2SA:
+        val = s->pom[2].sa;
+        break;
+
+    case PCIX0_PIM0SAL:
+        val = s->pim[0].sa;
+        break;
+    case PCIX0_PIM0LAL:
+        val = s->pim[0].la;
+        break;
+    case PCIX0_PIM0LAH:
+        val = s->pim[0].la >> 32;
+        break;
+    case PCIX0_PIM1SA:
+        val = s->pim[1].sa;
+        break;
+    case PCIX0_PIM1LAL:
+        val = s->pim[1].la;
+        break;
+    case PCIX0_PIM1LAH:
+        val = s->pim[1].la >> 32;
+        break;
+    case PCIX0_PIM2SAL:
+        val = s->pim[2].sa;
+        break;
+    case PCIX0_PIM2LAL:
+        val = s->pim[2].la;
+        break;
+    case PCIX0_PIM2LAH:
+        val = s->pim[2].la >> 32;
+        break;
+
+    case PCIX0_STS:
+        val = s->sts;
+        break;
+
+    case PCIX0_PIM0SAH:
+        val = s->pim[0].sa  >> 32;
+        break;
+    case PCIX0_PIM2SAH:
+        val = s->pim[2].sa  >> 32;
+        break;
+
+    default:
+        error_report("%s: invalid PCI internal register 0x%lx", __func__,
+                     (unsigned long)addr);
+        val = 0;
+    }
+
+    trace_ppc440_pcix_reg_read(addr, val);
+    return val;
+}
+
+static const MemoryRegionOps pci_reg_ops = {
+    .read = ppc440_pcix_reg_read4,
+    .write = ppc440_pcix_reg_write4,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void ppc440_pcix_reset(DeviceState *dev)
+{
+    struct PPC440PCIXState *s = PPC440_PCIX_HOST_BRIDGE(dev);
+    int i;
+
+    for (i = 0; i < PPC440_PCIX_NR_POMS; i++) {
+        ppc440_pcix_clear_region(get_system_memory(), &s->pom[i].mr);
+    }
+    for (i = 0; i < PPC440_PCIX_NR_PIMS; i++) {
+        ppc440_pcix_clear_region(&s->bm, &s->pim[i].mr);
+    }
+    memset(s->pom, 0, sizeof(s->pom));
+    memset(s->pim, 0, sizeof(s->pim));
+    for (i = 0; i < PPC440_PCIX_NR_PIMS; i++) {
+        s->pim[i].sa = 0xffffffff00000000ULL;
+    }
+    s->sts = 0;
+}
+
+/* All pins from each slot are tied to a single board IRQ.
+ * This may need further refactoring for other boards. */
+static int ppc440_pcix_map_irq(PCIDevice *pci_dev, int irq_num)
+{
+    int slot = pci_dev->devfn >> 3;
+    trace_ppc440_pcix_map_irq(pci_dev->devfn, irq_num, slot);
+    return slot - 1;
+}
+
+static void ppc440_pcix_set_irq(void *opaque, int irq_num, int level)
+{
+    qemu_irq *pci_irqs = opaque;
+
+    trace_ppc440_pcix_set_irq(irq_num);
+    if (irq_num < 0) {
+        error_report("%s: PCI irq %d", __func__, irq_num);
+        return;
+    }
+    qemu_set_irq(pci_irqs[irq_num], level);
+}
+
+static AddressSpace *ppc440_pcix_set_iommu(PCIBus *b, void *opaque, int devfn)
+{
+    PPC440PCIXState *s = opaque;
+
+    return &s->bm_as;
+}
+
+/* The default pci_host_data_{read,write} functions in pci/pci_host.c
+ * deny access to registers without bit 31 set but our clients want
+ * this to work so we have to override these here */
+static void pci_host_data_write(void *opaque, hwaddr addr,
+                                uint64_t val, unsigned len)
+{
+    PCIHostState *s = opaque;
+    pci_data_write(s->bus, s->config_reg | (addr & 3), val, len);
+}
+
+static uint64_t pci_host_data_read(void *opaque,
+                                   hwaddr addr, unsigned len)
+{
+    PCIHostState *s = opaque;
+    uint32_t val;
+    val = pci_data_read(s->bus, s->config_reg | (addr & 3), len);
+    return val;
+}
+
+const MemoryRegionOps ppc440_pcix_host_data_ops = {
+    .read = pci_host_data_read,
+    .write = pci_host_data_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static int ppc440_pcix_initfn(SysBusDevice *dev)
+{
+    PPC440PCIXState *s;
+    PCIHostState *h;
+    int i;
+
+    h = PCI_HOST_BRIDGE(dev);
+    s = PPC440_PCIX_HOST_BRIDGE(dev);
+
+    for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
+        sysbus_init_irq(dev, &s->irq[i]);
+    }
+
+    memory_region_init(&s->busmem, OBJECT(dev), "pci bus memory", UINT64_MAX);
+    h->bus = pci_register_root_bus(DEVICE(dev), NULL, ppc440_pcix_set_irq,
+                         ppc440_pcix_map_irq, s->irq, &s->busmem,
+                         get_system_io(), PCI_DEVFN(0, 0), 4, TYPE_PCI_BUS);
+
+    s->dev = pci_create_simple(h->bus, PCI_DEVFN(0, 0), "ppc4xx-host-bridge");
+
+    memory_region_init(&s->bm, OBJECT(s), "bm-ppc440-pcix", UINT64_MAX);
+    memory_region_add_subregion(&s->bm, 0x0, &s->busmem);
+    address_space_init(&s->bm_as, &s->bm, "pci-bm");
+    pci_setup_iommu(h->bus, ppc440_pcix_set_iommu, s);
+
+    memory_region_init(&s->container, OBJECT(s), "pci-container", PCI_ALL_SIZE);
+    memory_region_init_io(&h->conf_mem, OBJECT(s), &pci_host_conf_le_ops,
+                          h, "pci-conf-idx", 4);
+    memory_region_init_io(&h->data_mem, OBJECT(s), &ppc440_pcix_host_data_ops,
+                          h, "pci-conf-data", 4);
+    memory_region_init_io(&s->iomem, OBJECT(s), &pci_reg_ops, s,
+                          "pci.reg", PPC440_REG_SIZE);
+    memory_region_add_subregion(&s->container, PCIC0_CFGADDR, &h->conf_mem);
+    memory_region_add_subregion(&s->container, PCIC0_CFGDATA, &h->data_mem);
+    memory_region_add_subregion(&s->container, PPC440_REG_BASE, &s->iomem);
+    sysbus_init_mmio(dev, &s->container);
+
+    return 0;
+}
+
+static void ppc440_pcix_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    k->init = ppc440_pcix_initfn;
+    dc->reset = ppc440_pcix_reset;
+}
+
+static const TypeInfo ppc440_pcix_info = {
+    .name          = TYPE_PPC440_PCIX_HOST_BRIDGE,
+    .parent        = TYPE_PCI_HOST_BRIDGE,
+    .instance_size = sizeof(PPC440PCIXState),
+    .class_init    = ppc440_pcix_class_init,
+};
+
+static void ppc440_pcix_register_types(void)
+{
+    type_register_static(&ppc440_pcix_info);
+}
+
+type_init(ppc440_pcix_register_types)
diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events
index b7c3e64..b7036eb 100644
--- a/hw/ppc/trace-events
+++ b/hw/ppc/trace-events
@@ -99,3 +99,11 @@ mac99_uninorth_read(uint64_t addr, uint64_t value) "addr=0x%" PRIx64 " val=0x%"P
 # hw/ppc/ppc4xx_pci.c
 ppc4xx_pci_map_irq(int32_t devfn, int irq_num, int slot) "devfn 0x%x irq %d -> %d"
 ppc4xx_pci_set_irq(int irq_num) "PCI irq %d"
+
+# hw/ppc/ppc440_pcix.c
+ppc440_pcix_map_irq(int32_t devfn, int irq_num, int slot) "devfn 0x%x irq %d -> %d"
+ppc440_pcix_set_irq(int irq_num) "PCI irq %d"
+ppc440_pcix_update_pim(int idx, uint64_t size, uint64_t la) "Added window %d of size=0x%" PRIx64 " to CPU=0x%" PRIx64
+ppc440_pcix_update_pom(int idx, uint32_t size, uint64_t la, uint64_t pcia) "Added window %d of size=0x%x from CPU=0x%" PRIx64 " to PCI=0x%" PRIx64
+ppc440_pcix_reg_read(hwaddr addr, uint32_t val) "addr 0x%" PRIx64 " = 0x%" PRIx32
+ppc440_pcix_reg_write(hwaddr addr, uint64_t val) "addr 0x%" PRIx64 " = 0x%" PRIx64
-- 
2.7.6

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [Qemu-devel] [PATCH v2 3/3] ppc: Add aCube Sam460ex board
  2018-02-15 21:27 [Qemu-devel] [PATCH v2 0/3] Sam460ex emulation BALATON Zoltan
  2018-02-15 21:27 ` [Qemu-devel] [PATCH v2 1/3] ppc4xx: Add device models found in PPC440 core SoCs BALATON Zoltan
@ 2018-02-15 21:27 ` BALATON Zoltan
  2018-02-16  3:10   ` David Gibson
  2018-02-15 21:27 ` [Qemu-devel] [PATCH v2 2/3] ppc440: Add emulation of plb-pcix controller found in some 440 SoCs BALATON Zoltan
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 16+ messages in thread
From: BALATON Zoltan @ 2018-02-15 21:27 UTC (permalink / raw)
  To: qemu-devel, qemu-ppc; +Cc: Alexander Graf, David Gibson, Francois Revol

Add emulation of aCube Sam460ex board based on AMCC 460EX embedded SoC.
This is not a complete implementation yet with a lot of components
still missing but enough for the U-Boot firmware to start and to boot
a Linux kernel or AROS.

Signed-off-by: François Revol <revol@free.fr>
Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
---

v2:
- Rebased to latest changes on master
- Replaced printfs with error_report

 default-configs/ppc-softmmu.mak    |   2 +
 default-configs/ppcemb-softmmu.mak |   1 +
 hw/ppc/Makefile.objs               |   3 +-
 hw/ppc/sam460ex.c                  | 603 +++++++++++++++++++++++++++++++++++++
 4 files changed, 608 insertions(+), 1 deletion(-)
 create mode 100644 hw/ppc/sam460ex.c

diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak
index 76e29cf..4d7be45 100644
--- a/default-configs/ppc-softmmu.mak
+++ b/default-configs/ppc-softmmu.mak
@@ -21,6 +21,8 @@ CONFIG_E500=y
 CONFIG_OPENPIC_KVM=$(call land,$(CONFIG_E500),$(CONFIG_KVM))
 CONFIG_PLATFORM_BUS=y
 CONFIG_ETSEC=y
+# For Sam460ex
+CONFIG_USB_EHCI_SYSBUS=y
 CONFIG_SM501=y
 CONFIG_IDE_SII3112=y
 CONFIG_I2C=y
diff --git a/default-configs/ppcemb-softmmu.mak b/default-configs/ppcemb-softmmu.mak
index bc5e1b3..67d18b2 100644
--- a/default-configs/ppcemb-softmmu.mak
+++ b/default-configs/ppcemb-softmmu.mak
@@ -15,6 +15,7 @@ CONFIG_PTIMER=y
 CONFIG_I8259=y
 CONFIG_XILINX=y
 CONFIG_XILINX_ETHLITE=y
+CONFIG_USB_EHCI_SYSBUS=y
 CONFIG_SM501=y
 CONFIG_IDE_SII3112=y
 CONFIG_I2C=y
diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs
index bddc742..86d82a6 100644
--- a/hw/ppc/Makefile.objs
+++ b/hw/ppc/Makefile.objs
@@ -13,7 +13,8 @@ endif
 obj-$(CONFIG_PSERIES) += spapr_rtas_ddw.o
 # PowerPC 4xx boards
 obj-y += ppc4xx_devs.o ppc405_uc.o
-obj-$(CONFIG_PPC4XX) += ppc4xx_pci.o ppc405_boards.o ppc440_bamboo.o ppc440_pcix.o
+obj-$(CONFIG_PPC4XX) += ppc4xx_pci.o ppc405_boards.o
+obj-$(CONFIG_PPC4XX) += ppc440_bamboo.o ppc440_pcix.o ppc440_uc.o sam460ex.o
 # PReP
 obj-$(CONFIG_PREP) += prep.o
 obj-$(CONFIG_PREP) += prep_systemio.o
diff --git a/hw/ppc/sam460ex.c b/hw/ppc/sam460ex.c
new file mode 100644
index 0000000..ff99cf9
--- /dev/null
+++ b/hw/ppc/sam460ex.c
@@ -0,0 +1,603 @@
+/*
+ * QEMU aCube Sam460ex board emulation
+ *
+ * Copyright (c) 2012 François Revol
+ * Copyright (c) 2016-2018 BALATON Zoltan
+ *
+ * This file is derived from hw/ppc440_bamboo.c,
+ * the copyright for that material belongs to the original owners.
+ *
+ * This work is licensed under the GNU GPL license version 2 or later.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "qemu/cutils.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+#include "hw/hw.h"
+#include "sysemu/blockdev.h"
+#include "hw/boards.h"
+#include "sysemu/kvm.h"
+#include "kvm_ppc.h"
+#include "sysemu/device_tree.h"
+#include "sysemu/block-backend.h"
+#include "hw/loader.h"
+#include "elf.h"
+#include "exec/address-spaces.h"
+#include "exec/memory.h"
+#include "hw/ppc/ppc440.h"
+#include "hw/ppc/ppc405.h"
+#include "hw/block/flash.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/qtest.h"
+#include "hw/sysbus.h"
+#include "hw/char/serial.h"
+#include "hw/i2c/ppc4xx_i2c.h"
+#include "hw/i2c/smbus.h"
+#include "hw/usb/hcd-ehci.h"
+
+#define BINARY_DEVICE_TREE_FILE "sam460ex.dtb"
+#define UBOOT_FILENAME "u-boot-sam460-20100605.bin"
+/* to extract the official U-Boot bin from the updater: */
+/* dd bs=1 skip=$(($(stat -c '%s' updater/updater-460) - 0x80000)) \
+     if=updater/updater-460 of=u-boot-sam460-20100605.bin */
+
+/* from Sam460 U-Boot include/configs/Sam460ex.h */
+#define FLASH_BASE             0xfff00000
+#define FLASH_BASE_H           0x4
+#define FLASH_SIZE             (1 << 20)
+#define UBOOT_LOAD_BASE        0xfff80000
+#define UBOOT_SIZE             0x00080000
+#define UBOOT_ENTRY            0xfffffffc
+
+/* from U-Boot */
+#define EPAPR_MAGIC           (0x45504150)
+#define KERNEL_ADDR           0x1000000
+#define FDT_ADDR              0x1800000
+#define RAMDISK_ADDR          0x1900000
+
+/* Sam460ex IRQ MAP:
+   IRQ0  = ETH_INT
+   IRQ1  = FPGA_INT
+   IRQ2  = PCI_INT (PCIA, PCIB, PCIC, PCIB)
+   IRQ3  = FPGA_INT2
+   IRQ11 = RTC_INT
+   IRQ12 = SM502_INT
+*/
+
+#define SDRAM_NR_BANKS 4
+
+/* FIXME: See u-boot.git 8ac41e, also fix in ppc440_uc.c */
+static const unsigned int ppc460ex_sdram_bank_sizes[] = {
+    1024 << 20, 512 << 20, 256 << 20, 128 << 20, 64 << 20, 32 << 20, 0
+};
+
+struct boot_info {
+    uint32_t dt_base;
+    uint32_t dt_size;
+    uint32_t entry;
+};
+
+/*****************************************************************************/
+/* SPD eeprom content from mips_malta.c */
+
+struct _eeprom24c0x_t {
+  uint8_t tick;
+  uint8_t address;
+  uint8_t command;
+  uint8_t ack;
+  uint8_t scl;
+  uint8_t sda;
+  uint8_t data;
+  uint8_t contents[256];
+};
+
+typedef struct _eeprom24c0x_t eeprom24c0x_t;
+
+static eeprom24c0x_t spd_eeprom = {
+    .contents = {
+        /* 00000000: */ 0x80, 0x08, 0xFF, 0x0D, 0x0A, 0xFF, 0x40, 0x00,
+        /* 00000008: */ 0x04, 0x75, 0x54, 0x00, 0x82, 0x08, 0x00, 0x01,
+        /* 00000010: */ 0x8F, 0x04, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00,
+        /* 00000018: */ 0x00, 0x00, 0x00, 0x14, 0x0F, 0x14, 0x2D, 0xFF,
+        /* 00000020: */ 0x15, 0x08, 0x15, 0x08, 0x00, 0x00, 0x00, 0x00,
+        /* 00000028: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        /* 00000030: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        /* 00000038: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0xD0,
+        /* 00000040: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        /* 00000048: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        /* 00000050: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        /* 00000058: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        /* 00000060: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        /* 00000068: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        /* 00000070: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        /* 00000078: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xF4,
+    },
+};
+
+static void generate_eeprom_spd(uint8_t *eeprom, ram_addr_t ram_size)
+{
+    enum { SDR = 0x4, DDR1 = 0x7, DDR2 = 0x8 } type;
+    uint8_t *spd = spd_eeprom.contents;
+    uint8_t nbanks = 0;
+    uint16_t density = 0;
+    int i;
+
+    /* work in terms of MB */
+    ram_size >>= 20;
+
+    while ((ram_size >= 4) && (nbanks <= 2)) {
+        int sz_log2 = MIN(31 - clz32(ram_size), 14);
+        nbanks++;
+        density |= 1 << (sz_log2 - 2);
+        ram_size -= 1 << sz_log2;
+    }
+
+    /* split to 2 banks if possible */
+    if ((nbanks == 1) && (density > 1)) {
+        nbanks++;
+        density >>= 1;
+    }
+
+    if (density & 0xff00) {
+        density = (density & 0xe0) | ((density >> 8) & 0x1f);
+        type = DDR2;
+    } else if (!(density & 0x1f)) {
+        type = DDR2;
+    } else {
+        type = SDR;
+    }
+
+    if (ram_size) {
+        warn_report("SPD cannot represent final " RAM_ADDR_FMT "MB"
+                    " of SDRAM", ram_size);
+    }
+
+    /* fill in SPD memory information */
+    spd[2] = type;
+    spd[5] = nbanks;
+    spd[31] = density;
+
+    /* XXX: this is totally random */
+    spd[9] = 0x10; /* CAS tcyc */
+    spd[18] = 0x20; /* CAS bit */
+    spd[23] = 0x10; /* CAS tcyc */
+    spd[25] = 0x10; /* CAS tcyc */
+
+    /* checksum */
+    spd[63] = 0;
+    for (i = 0; i < 63; i++) {
+        spd[63] += spd[i];
+    }
+
+    /* copy for SMBUS */
+    memcpy(eeprom, spd, sizeof(spd_eeprom.contents));
+}
+
+static void generate_eeprom_serial(uint8_t *eeprom)
+{
+    int i, pos = 0;
+    uint8_t mac[6] = { 0x00 };
+    uint8_t sn[5] = { 0x01, 0x23, 0x45, 0x67, 0x89 };
+
+    /* version */
+    eeprom[pos++] = 0x01;
+
+    /* count */
+    eeprom[pos++] = 0x02;
+
+    /* MAC address */
+    eeprom[pos++] = 0x01; /* MAC */
+    eeprom[pos++] = 0x06; /* length */
+    memcpy(&eeprom[pos], mac, sizeof(mac));
+    pos += sizeof(mac);
+
+    /* serial number */
+    eeprom[pos++] = 0x02; /* serial */
+    eeprom[pos++] = 0x05; /* length */
+    memcpy(&eeprom[pos], sn, sizeof(sn));
+    pos += sizeof(sn);
+
+    /* checksum */
+    eeprom[pos] = 0;
+    for (i = 0; i < pos; i++) {
+        eeprom[pos] += eeprom[i];
+    }
+}
+
+/*****************************************************************************/
+
+static int sam460ex_load_uboot(void)
+{
+    DriveInfo *dinfo;
+    BlockBackend *blk = NULL;
+    hwaddr base = FLASH_BASE | ((hwaddr)FLASH_BASE_H << 32);
+    long bios_size = FLASH_SIZE;
+    int fl_sectors;
+
+    dinfo = drive_get(IF_PFLASH, 0, 0);
+    if (dinfo) {
+        blk = blk_by_legacy_dinfo(dinfo);
+        bios_size = blk_getlength(blk);
+    }
+    fl_sectors = (bios_size + 65535) >> 16;
+
+    if (!pflash_cfi01_register(base, NULL, "sam460ex.flash", bios_size,
+                               blk, (64 * 1024), fl_sectors,
+                               1, 0x89, 0x18, 0x0000, 0x0, 1)) {
+        error_report("qemu: Error registering flash memory.");
+        /* XXX: return an error instead? */
+        exit(1);
+    }
+
+    if (!blk) {
+        /*error_report("No flash image given with the 'pflash' parameter,"
+                " using default u-boot image");*/
+        base = UBOOT_LOAD_BASE | ((hwaddr)FLASH_BASE_H << 32);
+        rom_add_file_fixed(UBOOT_FILENAME, base, -1);
+    }
+
+    return 0;
+}
+
+static int sam460ex_load_device_tree(hwaddr addr,
+                                     uint32_t ramsize,
+                                     hwaddr initrd_base,
+                                     hwaddr initrd_size,
+                                     const char *kernel_cmdline)
+{
+    int ret = -1;
+    uint32_t mem_reg_property[] = { 0, 0, cpu_to_be32(ramsize) };
+    char *filename;
+    int fdt_size;
+    void *fdt;
+    uint32_t tb_freq = 400000000;
+    uint32_t clock_freq = 400000000;
+
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
+    if (!filename) {
+        goto out;
+    }
+    fdt = load_device_tree(filename, &fdt_size);
+    g_free(filename);
+    if (fdt == NULL) {
+        goto out;
+    }
+
+    /* Manipulate device tree in memory. */
+
+    ret = qemu_fdt_setprop(fdt, "/memory", "reg", mem_reg_property,
+                               sizeof(mem_reg_property));
+    if (ret < 0) {
+        error_report("couldn't set /memory/reg");
+    }
+
+    /* default FDT doesn't have a /chosen node... */
+    qemu_fdt_add_subnode(fdt, "/chosen");
+
+    ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start",
+                                    initrd_base);
+    if (ret < 0) {
+        error_report("couldn't set /chosen/linux,initrd-start");
+    }
+
+    ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
+                                    (initrd_base + initrd_size));
+    if (ret < 0) {
+        error_report("couldn't set /chosen/linux,initrd-end");
+    }
+
+    ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
+                                      kernel_cmdline);
+    if (ret < 0) {
+        error_report("couldn't set /chosen/bootargs");
+    }
+
+    /* Copy data from the host device tree into the guest. Since the guest can
+     * directly access the timebase without host involvement, we must expose
+     * the correct frequencies. */
+    if (kvm_enabled()) {
+        tb_freq = kvmppc_get_tbfreq();
+        clock_freq = kvmppc_get_clockfreq();
+    }
+
+    qemu_fdt_setprop_cell(fdt, "/cpus/cpu@0", "clock-frequency",
+                              clock_freq);
+    qemu_fdt_setprop_cell(fdt, "/cpus/cpu@0", "timebase-frequency",
+                              tb_freq);
+
+    rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
+    g_free(fdt);
+    ret = fdt_size;
+
+out:
+
+    return ret;
+}
+
+/* Create reset TLB entries for BookE, mapping only the flash memory.  */
+static void mmubooke_create_initial_mapping_uboot(CPUPPCState *env)
+{
+    ppcemb_tlb_t *tlb = &env->tlb.tlbe[0];
+
+    /* on reset the flash is mapped by a shadow TLB,
+     * but since we don't implement them we need to use
+     * the same values U-Boot will use to avoid a fault.
+     */
+    tlb->attr = 0;
+    tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
+    tlb->size = 0x10000000; /* up to 0xffffffff  */
+    tlb->EPN = 0xf0000000 & TARGET_PAGE_MASK;
+    tlb->RPN = (0xf0000000 & TARGET_PAGE_MASK) | 0x4;
+    tlb->PID = 0;
+}
+
+/* Create reset TLB entries for BookE, spanning the 32bit addr space.  */
+static void mmubooke_create_initial_mapping(CPUPPCState *env,
+                                     target_ulong va,
+                                     hwaddr pa)
+{
+    ppcemb_tlb_t *tlb = &env->tlb.tlbe[0];
+
+    tlb->attr = 0;
+    tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
+    tlb->size = 1 << 31; /* up to 0x80000000  */
+    tlb->EPN = va & TARGET_PAGE_MASK;
+    tlb->RPN = pa & TARGET_PAGE_MASK;
+    tlb->PID = 0;
+}
+
+static void main_cpu_reset(void *opaque)
+{
+    PowerPCCPU *cpu = opaque;
+    CPUPPCState *env = &cpu->env;
+    struct boot_info *bi = env->load_info;
+
+    cpu_reset(CPU(cpu));
+
+    /* either we have a kernel to boot or we jump to U-Boot */
+    if (bi->entry != UBOOT_ENTRY) {
+        env->gpr[1] = (16 << 20) - 8;
+        env->gpr[3] = FDT_ADDR;
+        env->nip = bi->entry;
+
+        /* Create a mapping for the kernel.  */
+        mmubooke_create_initial_mapping(env, 0, 0);
+        env->gpr[6] = tswap32(EPAPR_MAGIC);
+        env->gpr[7] = (16 << 20) - 8; /*bi->ima_size;*/
+
+    } else {
+        env->nip = UBOOT_ENTRY;
+        mmubooke_create_initial_mapping_uboot(env);
+    }
+}
+
+static void sam460ex_init(MachineState *machine)
+{
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *isa = g_new(MemoryRegion, 1);
+    MemoryRegion *ram_memories = g_new(MemoryRegion, SDRAM_NR_BANKS);
+    hwaddr ram_bases[SDRAM_NR_BANKS];
+    hwaddr ram_sizes[SDRAM_NR_BANKS];
+    MemoryRegion *l2cache_ram = g_new(MemoryRegion, 1);
+    qemu_irq *irqs, *uic[4];
+    PCIBus *pci_bus;
+    PowerPCCPU *cpu;
+    CPUPPCState *env;
+    PPC4xxI2CState *i2c[2];
+    hwaddr entry = UBOOT_ENTRY;
+    hwaddr loadaddr = 0;
+    target_long initrd_size = 0;
+    DeviceState *dev;
+    SysBusDevice *sbdev;
+    int success;
+    int i;
+    struct boot_info *boot_info;
+    const size_t smbus_eeprom_size = 8 * 256;
+    uint8_t *smbus_eeprom_buf = g_malloc0(smbus_eeprom_size);
+
+    cpu = POWERPC_CPU(cpu_create(machine->cpu_type));
+    env = &cpu->env;
+    if (env->mmu_model != POWERPC_MMU_BOOKE) {
+        error_report("Only MMU model BookE is supported by this machine.");
+        exit(1);
+    }
+
+#ifdef TARGET_PPCEMB
+    if (!qtest_enabled()) {
+        warn_report("qemu-system-ppcemb is deprecated, "
+                    "please use qemu-system-ppc instead.");
+    }
+#endif
+
+    qemu_register_reset(main_cpu_reset, cpu);
+    boot_info = g_malloc0(sizeof(*boot_info));
+    env->load_info = boot_info;
+
+    ppc_booke_timers_init(cpu, 50000000, 0);
+    ppc_dcr_init(env, NULL, NULL);
+
+    /* PLB arbitrer */
+    ppc4xx_plb_init(env);
+
+    /* interrupt controllers */
+    irqs = g_malloc0(sizeof(*irqs) * PPCUIC_OUTPUT_NB);
+    irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
+    irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
+    uic[0] = ppcuic_init(env, irqs, 0xc0, 0, 1);
+    uic[1] = ppcuic_init(env, &uic[0][30], 0xd0, 0, 1);
+    uic[2] = ppcuic_init(env, &uic[0][10], 0xe0, 0, 1);
+    uic[3] = ppcuic_init(env, &uic[0][16], 0xf0, 0, 1);
+
+    /* SDRAM controller */
+    memset(ram_bases, 0, sizeof(ram_bases));
+    memset(ram_sizes, 0, sizeof(ram_sizes));
+    /* put all RAM on first bank because board has one slot
+     * and firmware only checks that */
+    machine->ram_size = ppc4xx_sdram_adjust(machine->ram_size, 1,
+                                   ram_memories, ram_bases, ram_sizes,
+                                   ppc460ex_sdram_bank_sizes);
+
+    /* FIXME: does 460EX have ECC interrupts? */
+    ppc440_sdram_init(env, SDRAM_NR_BANKS, ram_memories,
+                      ram_bases, ram_sizes, 1);
+
+    /* generate SPD EEPROM data */
+    for (i = 0; i < SDRAM_NR_BANKS; i++) {
+        generate_eeprom_spd(&smbus_eeprom_buf[i * 256], ram_sizes[i]);
+    }
+    generate_eeprom_serial(&smbus_eeprom_buf[4 * 256]);
+    generate_eeprom_serial(&smbus_eeprom_buf[6 * 256]);
+
+    /* IIC controllers */
+    dev = sysbus_create_simple(TYPE_PPC4xx_I2C, 0x4ef600700, uic[0][2]);
+    i2c[0] = PPC4xx_I2C(dev);
+    object_property_set_bool(OBJECT(dev), true, "realized", NULL);
+    smbus_eeprom_init(i2c[0]->bus, 8, smbus_eeprom_buf, smbus_eeprom_size);
+    g_free(smbus_eeprom_buf);
+
+    dev = sysbus_create_simple(TYPE_PPC4xx_I2C, 0x4ef600800, uic[0][3]);
+    i2c[1] = PPC4xx_I2C(dev);
+
+    /* External bus controller */
+    ppc405_ebc_init(env);
+
+    /* CPR */
+    ppc4xx_cpr_init(env);
+
+    /* PLB to AHB bridge */
+    ppc4xx_ahb_init(env);
+
+    /* System DCRs */
+    ppc4xx_sdr_init(env);
+
+    /* MAL */
+    ppc4xx_mal_init(env, 4, 16, &uic[2][3]);
+
+    /* 256K of L2 cache as memory */
+    ppc4xx_l2sram_init(env);
+    /* FIXME: remove this after fixing l2sram mapping in ppc440_uc.c? */
+    memory_region_init_ram(l2cache_ram, NULL, "ppc440.l2cache_ram", 256 << 10,
+                           &error_abort);
+    memory_region_add_subregion(address_space_mem, 0x400000000LL, l2cache_ram);
+
+    /* USB */
+    sysbus_create_simple(TYPE_PPC4xx_EHCI, 0x4bffd0400, uic[2][29]);
+    dev = qdev_create(NULL, "sysbus-ohci");
+    qdev_prop_set_string(dev, "masterbus", "usb-bus.0");
+    qdev_prop_set_uint32(dev, "num-ports", 6);
+    qdev_init_nofail(dev);
+    sbdev = SYS_BUS_DEVICE(dev);
+    sysbus_mmio_map(sbdev, 0, 0x4bffd0000);
+    sysbus_connect_irq(sbdev, 0, uic[2][30]);
+    usb_create_simple(usb_bus_find(-1), "usb-kbd");
+    usb_create_simple(usb_bus_find(-1), "usb-mouse");
+
+    /* PCI bus */
+    ppc460ex_pcie_init(env);
+    /* FIXME: is this correct? */
+    dev = sysbus_create_varargs("ppc440-pcix-host", 0xc0ec00000,
+                                uic[1][0], uic[1][20], uic[1][21], uic[1][22],
+                                NULL);
+    pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
+    if (!pci_bus) {
+        error_report("couldn't create PCI controller!");
+        exit(1);
+    }
+    memory_region_init_alias(isa, NULL, "isa_mmio", get_system_io(),
+                             0, 0x10000);
+    memory_region_add_subregion(get_system_memory(), 0xc08000000, isa);
+
+    /* PCI devices */
+    pci_create_simple(pci_bus, PCI_DEVFN(6, 0), "sm501");
+    /* SoC has a single SATA port but we don't emulate that yet
+     * However, firmware and usual clients have driver for SiI311x
+     * so add one for convenience by default */
+    if (defaults_enabled()) {
+        pci_create_simple(pci_bus, -1, "sii3112");
+    }
+
+    /* SoC has 4 UARTs
+     * but board has only one wired and two are present in fdt */
+    if (serial_hds[0] != NULL) {
+        serial_mm_init(address_space_mem, 0x4ef600300, 0, uic[1][1],
+                       PPC_SERIAL_MM_BAUDBASE, serial_hds[0],
+                       DEVICE_BIG_ENDIAN);
+    }
+    if (serial_hds[1] != NULL) {
+        serial_mm_init(address_space_mem, 0x4ef600400, 0, uic[0][1],
+                       PPC_SERIAL_MM_BAUDBASE, serial_hds[1],
+                       DEVICE_BIG_ENDIAN);
+    }
+
+    /* Load U-Boot image. */
+    if (!machine->kernel_filename) {
+        success = sam460ex_load_uboot();
+        if (success < 0) {
+            error_report("qemu: could not load firmware");
+            exit(1);
+        }
+    }
+
+    /* Load kernel. */
+    if (machine->kernel_filename) {
+        success = load_uimage(machine->kernel_filename, &entry, &loadaddr,
+                              NULL, NULL, NULL);
+        if (success < 0) {
+            uint64_t elf_entry, elf_lowaddr;
+
+            success = load_elf(machine->kernel_filename, NULL, NULL, &elf_entry,
+                               &elf_lowaddr, NULL, 1, PPC_ELF_MACHINE, 0, 0);
+            entry = elf_entry;
+            loadaddr = elf_lowaddr;
+        }
+        /* XXX try again as binary */
+        if (success < 0) {
+            error_report("qemu: could not load kernel '%s'",
+                    machine->kernel_filename);
+            exit(1);
+        }
+    }
+
+    /* Load initrd. */
+    if (machine->initrd_filename) {
+        initrd_size = load_image_targphys(machine->initrd_filename,
+                                          RAMDISK_ADDR,
+                                          machine->ram_size - RAMDISK_ADDR);
+        if (initrd_size < 0) {
+            error_report("qemu: could not load ram disk '%s' at %x",
+                    machine->initrd_filename, RAMDISK_ADDR);
+            exit(1);
+        }
+    }
+
+    /* If we're loading a kernel directly, we must load the device tree too. */
+    if (machine->kernel_filename) {
+        int dt_size;
+
+        dt_size = sam460ex_load_device_tree(FDT_ADDR, machine->ram_size,
+                                    RAMDISK_ADDR, initrd_size,
+                                    machine->kernel_cmdline);
+        if (dt_size < 0) {
+            error_report("couldn't load device tree");
+            exit(1);
+        }
+
+        boot_info->dt_base = FDT_ADDR;
+        boot_info->dt_size = dt_size;
+    }
+
+    boot_info->entry = entry;
+}
+
+static void sam460ex_machine_init(MachineClass *mc)
+{
+    mc->desc = "aCube Sam460ex";
+    mc->init = sam460ex_init;
+    mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("460exb");
+    mc->default_ram_size = 512 * M_BYTE;
+}
+
+DEFINE_MACHINE("sam460ex", sam460ex_machine_init)
-- 
2.7.6

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [Qemu-devel] [PATCH v2 1/3] ppc4xx: Add device models found in PPC440 core SoCs
  2018-02-15 21:27 [Qemu-devel] [PATCH v2 0/3] Sam460ex emulation BALATON Zoltan
@ 2018-02-15 21:27 ` BALATON Zoltan
  2018-02-16  3:06   ` David Gibson
  2018-02-15 21:27 ` [Qemu-devel] [PATCH v2 3/3] ppc: Add aCube Sam460ex board BALATON Zoltan
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 16+ messages in thread
From: BALATON Zoltan @ 2018-02-15 21:27 UTC (permalink / raw)
  To: qemu-devel, qemu-ppc; +Cc: Alexander Graf, David Gibson, Francois Revol

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 36036 bytes --]

These devices are found in newer SoCs based on 440 core e.g. the 460EX
(http://www.embeddeddeveloper.com/assets/processors/amcc/datasheets/
PP460EX_DS2063.pdf)

Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
---

v2:
- Rebased to latest changes on master
- Removed printfs

 hw/ppc/ppc440.h            |   26 +
 hw/ppc/ppc440_uc.c         | 1159 ++++++++++++++++++++++++++++++++++++++++++++
 include/hw/pci/pcie_host.h |    2 +-
 3 files changed, 1186 insertions(+), 1 deletion(-)
 create mode 100644 hw/ppc/ppc440.h
 create mode 100644 hw/ppc/ppc440_uc.c

diff --git a/hw/ppc/ppc440.h b/hw/ppc/ppc440.h
new file mode 100644
index 0000000..ad27db1
--- /dev/null
+++ b/hw/ppc/ppc440.h
@@ -0,0 +1,26 @@
+/*
+ * QEMU PowerPC 440 shared definitions
+ *
+ * Copyright (c) 2012 François Revol
+ * Copyright (c) 2016-2018 BALATON Zoltan
+ *
+ * This work is licensed under the GNU GPL license version 2 or later.
+ *
+ */
+
+#ifndef PPC440_H
+#define PPC440_H
+
+#include "hw/ppc/ppc.h"
+
+void ppc4xx_l2sram_init(CPUPPCState *env);
+void ppc4xx_cpr_init(CPUPPCState *env);
+void ppc4xx_sdr_init(CPUPPCState *env);
+void ppc440_sdram_init(CPUPPCState *env, int nbanks,
+                       MemoryRegion *ram_memories,
+                       hwaddr *ram_bases, hwaddr *ram_sizes,
+                       int do_init);
+void ppc4xx_ahb_init(CPUPPCState *env);
+void ppc460ex_pcie_init(CPUPPCState *env);
+
+#endif /* PPC440_H */
diff --git a/hw/ppc/ppc440_uc.c b/hw/ppc/ppc440_uc.c
new file mode 100644
index 0000000..4e2523a
--- /dev/null
+++ b/hw/ppc/ppc440_uc.c
@@ -0,0 +1,1159 @@
+/*
+ * QEMU PowerPC 440 embedded processors emulation
+ *
+ * Copyright (c) 2012 François Revol
+ * Copyright (c) 2016-2018 BALATON Zoltan
+ *
+ * This work is licensed under the GNU GPL license version 2 or later.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "qemu/cutils.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+#include "cpu.h"
+#include "hw/hw.h"
+#include "exec/address-spaces.h"
+#include "exec/memory.h"
+#include "hw/ppc/ppc.h"
+#include "hw/pci/pci.h"
+#include "sysemu/block-backend.h"
+#include "hw/ppc/ppc440.h"
+
+/*****************************************************************************/
+/* L2 Cache as SRAM */
+/* FIXME:fix names */
+enum {
+    DCR_L2CACHE_BASE  = 0x30,
+    DCR_L2CACHE_CFG   = DCR_L2CACHE_BASE,
+    DCR_L2CACHE_CMD,
+    DCR_L2CACHE_ADDR,
+    DCR_L2CACHE_DATA,
+    DCR_L2CACHE_STAT,
+    DCR_L2CACHE_CVER,
+    DCR_L2CACHE_SNP0,
+    DCR_L2CACHE_SNP1,
+    DCR_L2CACHE_END   = DCR_L2CACHE_SNP1,
+};
+
+/* base is 460ex-specific, cf. U-Boot, ppc4xx-isram.h */
+enum {
+    DCR_ISRAM0_BASE   = 0x20,
+    DCR_ISRAM0_SB0CR  = DCR_ISRAM0_BASE,
+    DCR_ISRAM0_SB1CR,
+    DCR_ISRAM0_SB2CR,
+    DCR_ISRAM0_SB3CR,
+    DCR_ISRAM0_BEAR,
+    DCR_ISRAM0_BESR0,
+    DCR_ISRAM0_BESR1,
+    DCR_ISRAM0_PMEG,
+    DCR_ISRAM0_CID,
+    DCR_ISRAM0_REVID,
+    DCR_ISRAM0_DPC,
+    DCR_ISRAM0_END    = DCR_ISRAM0_DPC
+};
+
+enum {
+    DCR_ISRAM1_BASE   = 0xb0,
+    DCR_ISRAM1_SB0CR  = DCR_ISRAM1_BASE,
+    /* single bank */
+    DCR_ISRAM1_BEAR   = DCR_ISRAM1_BASE + 0x04,
+    DCR_ISRAM1_BESR0,
+    DCR_ISRAM1_BESR1,
+    DCR_ISRAM1_PMEG,
+    DCR_ISRAM1_CID,
+    DCR_ISRAM1_REVID,
+    DCR_ISRAM1_DPC,
+    DCR_ISRAM1_END    = DCR_ISRAM1_DPC
+};
+
+typedef struct ppc4xx_l2sram_t {
+    MemoryRegion bank[4];
+    uint32_t l2cache[8];
+    uint32_t isram0[11];
+} ppc4xx_l2sram_t;
+
+#ifdef MAP_L2SRAM
+static void l2sram_update_mappings(ppc4xx_l2sram_t *l2sram,
+                                   uint32_t isarc, uint32_t isacntl,
+                                   uint32_t dsarc, uint32_t dsacntl)
+{
+    if (l2sram->isarc != isarc ||
+        (l2sram->isacntl & 0x80000000) != (isacntl & 0x80000000)) {
+        if (l2sram->isacntl & 0x80000000) {
+            /* Unmap previously assigned memory region */
+            memory_region_del_subregion(get_system_memory(),
+                                        &l2sram->isarc_ram);
+        }
+        if (isacntl & 0x80000000) {
+            /* Map new instruction memory region */
+            memory_region_add_subregion(get_system_memory(), isarc,
+                                        &l2sram->isarc_ram);
+        }
+    }
+    if (l2sram->dsarc != dsarc ||
+        (l2sram->dsacntl & 0x80000000) != (dsacntl & 0x80000000)) {
+        if (l2sram->dsacntl & 0x80000000) {
+            /* Beware not to unmap the region we just mapped */
+            if (!(isacntl & 0x80000000) || l2sram->dsarc != isarc) {
+                /* Unmap previously assigned memory region */
+                memory_region_del_subregion(get_system_memory(),
+                                            &l2sram->dsarc_ram);
+            }
+        }
+        if (dsacntl & 0x80000000) {
+            /* Beware not to remap the region we just mapped */
+            if (!(isacntl & 0x80000000) || dsarc != isarc) {
+                /* Map new data memory region */
+                memory_region_add_subregion(get_system_memory(), dsarc,
+                                            &l2sram->dsarc_ram);
+            }
+        }
+    }
+}
+#endif
+
+static uint32_t dcr_read_l2sram(void *opaque, int dcrn)
+{
+    ppc4xx_l2sram_t *l2sram = opaque;
+    uint32_t ret = 0;
+
+    switch (dcrn) {
+    case DCR_L2CACHE_CFG:
+    case DCR_L2CACHE_CMD:
+    case DCR_L2CACHE_ADDR:
+    case DCR_L2CACHE_DATA:
+    case DCR_L2CACHE_STAT:
+    case DCR_L2CACHE_CVER:
+    case DCR_L2CACHE_SNP0:
+    case DCR_L2CACHE_SNP1:
+        ret = l2sram->l2cache[dcrn - DCR_L2CACHE_BASE];
+        break;
+
+    case DCR_ISRAM0_SB0CR:
+    case DCR_ISRAM0_SB1CR:
+    case DCR_ISRAM0_SB2CR:
+    case DCR_ISRAM0_SB3CR:
+    case DCR_ISRAM0_BEAR:
+    case DCR_ISRAM0_BESR0:
+    case DCR_ISRAM0_BESR1:
+    case DCR_ISRAM0_PMEG:
+    case DCR_ISRAM0_CID:
+    case DCR_ISRAM0_REVID:
+    case DCR_ISRAM0_DPC:
+        ret = l2sram->isram0[dcrn - DCR_ISRAM0_BASE];
+        break;
+
+    default:
+        break;
+    }
+
+    return ret;
+}
+
+static void dcr_write_l2sram(void *opaque, int dcrn, uint32_t val)
+{
+    /*ppc4xx_l2sram_t *l2sram = opaque;*/
+    /* FIXME: Actually handle L2 cache mapping */
+
+    switch (dcrn) {
+    case DCR_L2CACHE_CFG:
+    case DCR_L2CACHE_CMD:
+    case DCR_L2CACHE_ADDR:
+    case DCR_L2CACHE_DATA:
+    case DCR_L2CACHE_STAT:
+    case DCR_L2CACHE_CVER:
+    case DCR_L2CACHE_SNP0:
+    case DCR_L2CACHE_SNP1:
+        /*l2sram->l2cache[dcrn - DCR_L2CACHE_BASE] = val;*/
+        break;
+
+    case DCR_ISRAM0_SB0CR:
+    case DCR_ISRAM0_SB1CR:
+    case DCR_ISRAM0_SB2CR:
+    case DCR_ISRAM0_SB3CR:
+    case DCR_ISRAM0_BEAR:
+    case DCR_ISRAM0_BESR0:
+    case DCR_ISRAM0_BESR1:
+    case DCR_ISRAM0_PMEG:
+    case DCR_ISRAM0_CID:
+    case DCR_ISRAM0_REVID:
+    case DCR_ISRAM0_DPC:
+        /*l2sram->isram0[dcrn - DCR_L2CACHE_BASE] = val;*/
+        break;
+
+    case DCR_ISRAM1_SB0CR:
+    case DCR_ISRAM1_BEAR:
+    case DCR_ISRAM1_BESR0:
+    case DCR_ISRAM1_BESR1:
+    case DCR_ISRAM1_PMEG:
+    case DCR_ISRAM1_CID:
+    case DCR_ISRAM1_REVID:
+    case DCR_ISRAM1_DPC:
+        /*l2sram->isram1[dcrn - DCR_L2CACHE_BASE] = val;*/
+        break;
+    }
+    /*l2sram_update_mappings(l2sram, isarc, isacntl, dsarc, dsacntl);*/
+}
+
+static void l2sram_reset(void *opaque)
+{
+    ppc4xx_l2sram_t *l2sram = opaque;
+
+    memset(l2sram->l2cache, 0, sizeof(l2sram->l2cache));
+    l2sram->l2cache[DCR_L2CACHE_STAT - DCR_L2CACHE_BASE] = 0x80000000;
+    memset(l2sram->isram0, 0, sizeof(l2sram->isram0));
+    /*l2sram_update_mappings(l2sram, isarc, isacntl, dsarc, dsacntl);*/
+}
+
+void ppc4xx_l2sram_init(CPUPPCState *env)
+{
+    ppc4xx_l2sram_t *l2sram;
+
+    l2sram = g_malloc0(sizeof(*l2sram));
+    /* XXX: Size is 4*64kB for 460ex, cf. U-Boot, ppc4xx-isram.h */
+    memory_region_init_ram(&l2sram->bank[0], NULL, "ppc4xx.l2sram_bank0",
+                           64 * K_BYTE, &error_abort);
+    memory_region_init_ram(&l2sram->bank[1], NULL, "ppc4xx.l2sram_bank1",
+                           64 * K_BYTE, &error_abort);
+    memory_region_init_ram(&l2sram->bank[2], NULL, "ppc4xx.l2sram_bank2",
+                           64 * K_BYTE, &error_abort);
+    memory_region_init_ram(&l2sram->bank[3], NULL, "ppc4xx.l2sram_bank3",
+                           64 * K_BYTE, &error_abort);
+    qemu_register_reset(&l2sram_reset, l2sram);
+    ppc_dcr_register(env, DCR_L2CACHE_CFG,
+                     l2sram, &dcr_read_l2sram, &dcr_write_l2sram);
+    ppc_dcr_register(env, DCR_L2CACHE_CMD,
+                     l2sram, &dcr_read_l2sram, &dcr_write_l2sram);
+    ppc_dcr_register(env, DCR_L2CACHE_ADDR,
+                     l2sram, &dcr_read_l2sram, &dcr_write_l2sram);
+    ppc_dcr_register(env, DCR_L2CACHE_DATA,
+                     l2sram, &dcr_read_l2sram, &dcr_write_l2sram);
+    ppc_dcr_register(env, DCR_L2CACHE_STAT,
+                     l2sram, &dcr_read_l2sram, &dcr_write_l2sram);
+    ppc_dcr_register(env, DCR_L2CACHE_CVER,
+                     l2sram, &dcr_read_l2sram, &dcr_write_l2sram);
+    ppc_dcr_register(env, DCR_L2CACHE_SNP0,
+                     l2sram, &dcr_read_l2sram, &dcr_write_l2sram);
+    ppc_dcr_register(env, DCR_L2CACHE_SNP1,
+                     l2sram, &dcr_read_l2sram, &dcr_write_l2sram);
+
+    ppc_dcr_register(env, DCR_ISRAM0_SB0CR,
+                     l2sram, &dcr_read_l2sram, &dcr_write_l2sram);
+    ppc_dcr_register(env, DCR_ISRAM0_SB1CR,
+                     l2sram, &dcr_read_l2sram, &dcr_write_l2sram);
+    ppc_dcr_register(env, DCR_ISRAM0_SB2CR,
+                     l2sram, &dcr_read_l2sram, &dcr_write_l2sram);
+    ppc_dcr_register(env, DCR_ISRAM0_SB3CR,
+                     l2sram, &dcr_read_l2sram, &dcr_write_l2sram);
+    ppc_dcr_register(env, DCR_ISRAM0_PMEG,
+                     l2sram, &dcr_read_l2sram, &dcr_write_l2sram);
+    ppc_dcr_register(env, DCR_ISRAM0_DPC,
+                     l2sram, &dcr_read_l2sram, &dcr_write_l2sram);
+
+    ppc_dcr_register(env, DCR_ISRAM1_SB0CR,
+                     l2sram, &dcr_read_l2sram, &dcr_write_l2sram);
+    ppc_dcr_register(env, DCR_ISRAM1_PMEG,
+                     l2sram, &dcr_read_l2sram, &dcr_write_l2sram);
+    ppc_dcr_register(env, DCR_ISRAM1_DPC,
+                     l2sram, &dcr_read_l2sram, &dcr_write_l2sram);
+}
+
+/*****************************************************************************/
+/* Clocking Power on Reset */
+enum {
+    CPR0_CFGADDR = 0xC,
+    CPR0_CFGDATA = 0xD,
+
+    CPR0_PLLD = 0x060,
+    CPR0_PLBED = 0x080,
+    CPR0_OPBD = 0x0C0,
+    CPR0_PERD = 0x0E0,
+    CPR0_AHBD = 0x100,
+};
+
+typedef struct ppc4xx_cpr_t {
+    uint32_t addr;
+} ppc4xx_cpr_t;
+
+static uint32_t dcr_read_cpr(void *opaque, int dcrn)
+{
+    ppc4xx_cpr_t *cpr = opaque;
+    uint32_t ret = 0;
+
+    switch (dcrn) {
+    case CPR0_CFGADDR:
+        ret = cpr->addr;
+        break;
+    case CPR0_CFGDATA:
+        switch (cpr->addr) {
+        case CPR0_PLLD:
+            ret = (0xb5 << 24) | (1 << 16) | (9 << 8);
+            break;
+        case CPR0_PLBED:
+            ret = (5 << 24);
+            break;
+        case CPR0_OPBD:
+            ret = (2 << 24);
+            break;
+        case CPR0_PERD:
+        case CPR0_AHBD:
+            ret = (1 << 24);
+            break;
+        default:
+            break;
+        }
+        break;
+    default:
+        break;
+    }
+
+    return ret;
+}
+
+static void dcr_write_cpr(void *opaque, int dcrn, uint32_t val)
+{
+    ppc4xx_cpr_t *cpr = opaque;
+
+    switch (dcrn) {
+    case CPR0_CFGADDR:
+        cpr->addr = val;
+        break;
+    case CPR0_CFGDATA:
+        break;
+    default:
+        break;
+    }
+}
+
+static void ppc4xx_cpr_reset(void *opaque)
+{
+    ppc4xx_cpr_t *cpr = opaque;
+
+    cpr->addr = 0;
+}
+
+void ppc4xx_cpr_init(CPUPPCState *env)
+{
+    ppc4xx_cpr_t *cpr;
+
+    cpr = g_malloc0(sizeof(*cpr));
+    ppc_dcr_register(env, CPR0_CFGADDR, cpr, &dcr_read_cpr, &dcr_write_cpr);
+    ppc_dcr_register(env, CPR0_CFGDATA, cpr, &dcr_read_cpr, &dcr_write_cpr);
+    qemu_register_reset(ppc4xx_cpr_reset, cpr);
+}
+
+/*****************************************************************************/
+/* System DCRs */
+typedef struct ppc4xx_sdr_t ppc4xx_sdr_t;
+struct ppc4xx_sdr_t {
+    uint32_t addr;
+};
+
+enum {
+    SDR0_CFGADDR = 0x00e,
+    SDR0_CFGDATA,
+    SDR0_STRP0 = 0x020,
+    SDR0_STRP1,
+    SDR0_102 = 0x66,
+    SDR0_103,
+    SDR0_128 = 0x80,
+    SDR0_ECID3 = 0x083,
+    SDR0_DDR0 = 0x0e1,
+    SDR0_USB0 = 0x320,
+};
+
+enum {
+    PESDR0_LOOP = 0x303,
+    PESDR0_RCSSET,
+    PESDR0_RCSSTS,
+    PESDR0_RSTSTA = 0x310,
+    PESDR1_LOOP = 0x343,
+    PESDR1_RCSSET,
+    PESDR1_RCSSTS,
+    PESDR1_RSTSTA = 0x365,
+};
+
+#define SDR0_DDR0_DDRM_ENCODE(n)  ((((unsigned long)(n)) & 0x03) << 29)
+#define SDR0_DDR0_DDRM_DDR1       0x20000000
+#define SDR0_DDR0_DDRM_DDR2       0x40000000
+
+static uint32_t dcr_read_sdr(void *opaque, int dcrn)
+{
+    ppc4xx_sdr_t *sdr = opaque;
+    uint32_t ret = 0;
+
+    switch (dcrn) {
+    case SDR0_CFGADDR:
+        ret = sdr->addr;
+        break;
+    case SDR0_CFGDATA:
+        switch (sdr->addr) {
+        case SDR0_STRP0:
+            /* FIXME: Is this correct? This breaks timing in U-Boot */
+            ret = 0; /*(0xb5 << 8) | (1 << 4) | 9 */
+            break;
+        case SDR0_STRP1:
+            ret = (5 << 29) | (2 << 26) | (1 << 24);
+            break;
+        case SDR0_ECID3:
+            ret = 1 << 20; /* No Security/Kasumi support */
+            break;
+        case SDR0_DDR0:
+            ret = SDR0_DDR0_DDRM_ENCODE(1) | SDR0_DDR0_DDRM_DDR1;
+            break;
+        case PESDR0_RCSSET:
+        case PESDR1_RCSSET:
+            ret = (1 << 24) | (1 << 16);
+            break;
+        case PESDR0_RCSSTS:
+        case PESDR1_RCSSTS:
+            ret = (1 << 16) | (1 << 12);
+            break;
+        case PESDR0_RSTSTA:
+        case PESDR1_RSTSTA:
+            ret = 1;
+            break;
+        case PESDR0_LOOP:
+        case PESDR1_LOOP:
+            ret = 1 << 12;
+            break;
+        default:
+            break;
+        }
+        break;
+    default:
+        break;
+    }
+
+    return ret;
+}
+
+static void dcr_write_sdr(void *opaque, int dcrn, uint32_t val)
+{
+    ppc4xx_sdr_t *sdr = opaque;
+
+    switch (dcrn) {
+    case SDR0_CFGADDR:
+        sdr->addr = val;
+        break;
+    case SDR0_CFGDATA:
+        switch (sdr->addr) {
+        case 0x00: /* B0CR */
+            break;
+        default:
+            break;
+        }
+        break;
+    default:
+        break;
+    }
+}
+
+static void sdr_reset(void *opaque)
+{
+    ppc4xx_sdr_t *sdr = opaque;
+
+    sdr->addr = 0;
+}
+
+void ppc4xx_sdr_init(CPUPPCState *env)
+{
+    ppc4xx_sdr_t *sdr;
+
+    sdr = g_malloc0(sizeof(*sdr));
+    qemu_register_reset(&sdr_reset, sdr);
+    ppc_dcr_register(env, SDR0_CFGADDR,
+                     sdr, &dcr_read_sdr, &dcr_write_sdr);
+    ppc_dcr_register(env, SDR0_CFGDATA,
+                     sdr, &dcr_read_sdr, &dcr_write_sdr);
+    ppc_dcr_register(env, SDR0_102,
+                     sdr, &dcr_read_sdr, &dcr_write_sdr);
+    ppc_dcr_register(env, SDR0_103,
+                     sdr, &dcr_read_sdr, &dcr_write_sdr);
+    ppc_dcr_register(env, SDR0_128,
+                     sdr, &dcr_read_sdr, &dcr_write_sdr);
+    ppc_dcr_register(env, SDR0_USB0,
+                     sdr, &dcr_read_sdr, &dcr_write_sdr);
+}
+
+/*****************************************************************************/
+/* SDRAM controller */
+typedef 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 bcr[4];
+} ppc4xx_sdram_t;
+
+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,
+};
+
+/* 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_bcr(hwaddr ram_base, hwaddr ram_size)
+{
+    uint32_t bcr;
+
+    switch (ram_size) {
+    case (8 * M_BYTE):
+        bcr = 0xffc0;
+        break;
+    case (16 * M_BYTE):
+        bcr = 0xff80;
+        break;
+    case (32 * M_BYTE):
+        bcr = 0xff00;
+        break;
+    case (64 * M_BYTE):
+        bcr = 0xfe00;
+        break;
+    case (128 * M_BYTE):
+        bcr = 0xfc00;
+        break;
+    case (256 * M_BYTE):
+        bcr = 0xf800;
+        break;
+    case (512 * M_BYTE):
+        bcr = 0xf000;
+        break;
+    case (1 * G_BYTE):
+        bcr = 0xe000;
+        break;
+    default:
+        error_report("invalid RAM size " TARGET_FMT_plx, ram_size);
+        return 0;
+    }
+    bcr |= ram_base & 0xFF800000;
+    bcr |= 1;
+
+    return bcr;
+}
+
+static inline hwaddr sdram_base(uint32_t bcr)
+{
+    return bcr & 0xFF800000;
+}
+
+static target_ulong sdram_size(uint32_t bcr)
+{
+    target_ulong size;
+    int sh;
+
+    sh = 1024 - ((bcr >> 6) & 0x3ff);
+    if (sh == 0) {
+        size = -1;
+    } else {
+        size = 8 * M_BYTE * sh;
+    }
+
+    return size;
+}
+
+static void sdram_set_bcr(ppc4xx_sdram_t *sdram,
+                          uint32_t *bcrp, uint32_t bcr, int enabled)
+{
+    unsigned n = bcrp - sdram->bcr;
+
+    if (*bcrp & 1) {
+        /* Unmap RAM */
+        memory_region_del_subregion(get_system_memory(),
+                                    &sdram->containers[n]);
+        memory_region_del_subregion(&sdram->containers[n],
+                                    &sdram->ram_memories[n]);
+        object_unparent(OBJECT(&sdram->containers[n]));
+    }
+    *bcrp = bcr & 0xFFDEE001;
+    if (enabled && (bcr & 1)) {
+        memory_region_init(&sdram->containers[n], NULL, "sdram-containers",
+                           sdram_size(bcr));
+        memory_region_add_subregion(&sdram->containers[n], 0,
+                                    &sdram->ram_memories[n]);
+        memory_region_add_subregion(get_system_memory(),
+                                    sdram_base(bcr),
+                                    &sdram->containers[n]);
+    }
+}
+
+static void sdram_map_bcr(ppc4xx_sdram_t *sdram)
+{
+    int i;
+
+    for (i = 0; i < sdram->nbanks; i++) {
+        if (sdram->ram_sizes[i] != 0) {
+            sdram_set_bcr(sdram,
+                          &sdram->bcr[i],
+                          sdram_bcr(sdram->ram_bases[i], sdram->ram_sizes[i]),
+                          1);
+        } else {
+            sdram_set_bcr(sdram, &sdram->bcr[i], 0, 0);
+        }
+    }
+}
+
+static uint32_t dcr_read_sdram(void *opaque, int dcrn)
+{
+    ppc4xx_sdram_t *sdram = opaque;
+    uint32_t ret = 0;
+
+    switch (dcrn) {
+    case SDRAM_R0BAS:
+    case SDRAM_R1BAS:
+    case SDRAM_R2BAS:
+    case SDRAM_R3BAS:
+        ret = sdram_bcr(sdram->ram_bases[dcrn - SDRAM_R0BAS],
+                        sdram->ram_sizes[dcrn - SDRAM_R0BAS]);
+        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 = 0x08000000;
+            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;
+}
+
+static void dcr_write_sdram(void *opaque, int dcrn, uint32_t val)
+{
+    ppc4xx_sdram_t *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;
+        default:
+            break;
+        }
+        break;
+    default:
+        break;
+    }
+}
+
+static void sdram_reset(void *opaque)
+{
+    ppc4xx_sdram_t *sdram = opaque;
+
+    sdram->addr = 0;
+}
+
+void ppc440_sdram_init(CPUPPCState *env, int nbanks,
+                       MemoryRegion *ram_memories,
+                       hwaddr *ram_bases, hwaddr *ram_sizes,
+                       int do_init)
+{
+    ppc4xx_sdram_t *sdram;
+
+    sdram = g_malloc0(sizeof(*sdram));
+    sdram->nbanks = nbanks;
+    sdram->ram_memories = ram_memories;
+    memcpy(sdram->ram_bases, ram_bases, nbanks * sizeof(hwaddr));
+    memcpy(sdram->ram_sizes, ram_sizes, nbanks * sizeof(hwaddr));
+    qemu_register_reset(&sdram_reset, sdram);
+    ppc_dcr_register(env, SDRAM0_CFGADDR,
+                     sdram, &dcr_read_sdram, &dcr_write_sdram);
+    ppc_dcr_register(env, SDRAM0_CFGDATA,
+                     sdram, &dcr_read_sdram, &dcr_write_sdram);
+    if (do_init) {
+        sdram_map_bcr(sdram);
+    }
+
+    ppc_dcr_register(env, SDRAM_R0BAS,
+                     sdram, &dcr_read_sdram, &dcr_write_sdram);
+    ppc_dcr_register(env, SDRAM_R1BAS,
+                     sdram, &dcr_read_sdram, &dcr_write_sdram);
+    ppc_dcr_register(env, SDRAM_R2BAS,
+                     sdram, &dcr_read_sdram, &dcr_write_sdram);
+    ppc_dcr_register(env, SDRAM_R3BAS,
+                     sdram, &dcr_read_sdram, &dcr_write_sdram);
+    ppc_dcr_register(env, SDRAM_CONF1HB,
+                     sdram, &dcr_read_sdram, &dcr_write_sdram);
+    ppc_dcr_register(env, SDRAM_PLBADDULL,
+                     sdram, &dcr_read_sdram, &dcr_write_sdram);
+    ppc_dcr_register(env, SDRAM_CONF1LL,
+                     sdram, &dcr_read_sdram, &dcr_write_sdram);
+    ppc_dcr_register(env, SDRAM_CONFPATHB,
+                     sdram, &dcr_read_sdram, &dcr_write_sdram);
+    ppc_dcr_register(env, SDRAM_PLBADDUHB,
+                     sdram, &dcr_read_sdram, &dcr_write_sdram);
+}
+
+/*****************************************************************************/
+/* PLB to AHB bridge */
+enum {
+    AHB_TOP    = 0xA4,
+    AHB_BOT    = 0xA5,
+};
+
+typedef struct ppc4xx_ahb_t {
+    uint32_t top;
+    uint32_t bot;
+} ppc4xx_ahb_t;
+
+static uint32_t dcr_read_ahb(void *opaque, int dcrn)
+{
+    ppc4xx_ahb_t *ahb = opaque;
+    uint32_t ret = 0;
+
+    switch (dcrn) {
+    case AHB_TOP:
+        ret = ahb->top;
+        break;
+    case AHB_BOT:
+        ret = ahb->bot;
+        break;
+    default:
+        break;
+    }
+
+    return ret;
+}
+
+static void dcr_write_ahb(void *opaque, int dcrn, uint32_t val)
+{
+    ppc4xx_ahb_t *ahb = opaque;
+
+    switch (dcrn) {
+    case AHB_TOP:
+        ahb->top = val;
+        break;
+    case AHB_BOT:
+        ahb->bot = val;
+        break;
+    }
+}
+
+static void ppc4xx_ahb_reset(void *opaque)
+{
+    ppc4xx_ahb_t *ahb = opaque;
+
+    /* No error */
+    ahb->top = 0;
+    ahb->bot = 0;
+}
+
+void ppc4xx_ahb_init(CPUPPCState *env)
+{
+    ppc4xx_ahb_t *ahb;
+
+    ahb = g_malloc0(sizeof(*ahb));
+    ppc_dcr_register(env, AHB_TOP, ahb, &dcr_read_ahb, &dcr_write_ahb);
+    ppc_dcr_register(env, AHB_BOT, ahb, &dcr_read_ahb, &dcr_write_ahb);
+    qemu_register_reset(ppc4xx_ahb_reset, ahb);
+}
+
+/*****************************************************************************/
+/* PCI Express controller */
+/* FIXME: This is not complete and does not work, only implemented partially
+ * to allow firmware and guests to find an empty bus. Cards should use PCI.
+ */
+#include "hw/pci/pcie_host.h"
+
+#define TYPE_PPC460EX_PCIE_HOST "ppc460ex-pcie-host"
+#define PPC460EX_PCIE_HOST(obj) \
+    OBJECT_CHECK(PPC460EXPCIEState, (obj), TYPE_PPC460EX_PCIE_HOST)
+
+typedef struct PPC460EXPCIEState {
+    PCIExpressHost host;
+
+    MemoryRegion iomem;
+    qemu_irq irq[4];
+    int32_t dcrn_base;
+
+    uint64_t cfg_base;
+    uint32_t cfg_mask;
+    uint64_t msg_base;
+    uint32_t msg_mask;
+    uint64_t omr1_base;
+    uint64_t omr1_mask;
+    uint64_t omr2_base;
+    uint64_t omr2_mask;
+    uint64_t omr3_base;
+    uint64_t omr3_mask;
+    uint64_t reg_base;
+    uint32_t reg_mask;
+    uint32_t special;
+    uint32_t cfg;
+} PPC460EXPCIEState;
+
+#define DCRN_PCIE0_BASE 0x100
+#define DCRN_PCIE1_BASE 0x120
+
+enum {
+    PEGPL_CFGBAH = 0x0,
+    PEGPL_CFGBAL,
+    PEGPL_CFGMSK,
+    PEGPL_MSGBAH,
+    PEGPL_MSGBAL,
+    PEGPL_MSGMSK,
+    PEGPL_OMR1BAH,
+    PEGPL_OMR1BAL,
+    PEGPL_OMR1MSKH,
+    PEGPL_OMR1MSKL,
+    PEGPL_OMR2BAH,
+    PEGPL_OMR2BAL,
+    PEGPL_OMR2MSKH,
+    PEGPL_OMR2MSKL,
+    PEGPL_OMR3BAH,
+    PEGPL_OMR3BAL,
+    PEGPL_OMR3MSKH,
+    PEGPL_OMR3MSKL,
+    PEGPL_REGBAH,
+    PEGPL_REGBAL,
+    PEGPL_REGMSK,
+    PEGPL_SPECIAL,
+    PEGPL_CFG,
+};
+
+static uint32_t dcr_read_pcie(void *opaque, int dcrn)
+{
+    PPC460EXPCIEState *state = opaque;
+    uint32_t ret = 0;
+
+    switch (dcrn - state->dcrn_base) {
+    case PEGPL_CFGBAH:
+        ret = state->cfg_base >> 32;
+        break;
+    case PEGPL_CFGBAL:
+        ret = state->cfg_base;
+        break;
+    case PEGPL_CFGMSK:
+        ret = state->cfg_mask;
+        break;
+    case PEGPL_MSGBAH:
+        ret = state->msg_base >> 32;
+        break;
+    case PEGPL_MSGBAL:
+        ret = state->msg_base;
+        break;
+    case PEGPL_MSGMSK:
+        ret = state->msg_mask;
+        break;
+    case PEGPL_OMR1BAH:
+        ret = state->omr1_base >> 32;
+        break;
+    case PEGPL_OMR1BAL:
+        ret = state->omr1_base;
+        break;
+    case PEGPL_OMR1MSKH:
+        ret = state->omr1_mask >> 32;
+        break;
+    case PEGPL_OMR1MSKL:
+        ret = state->omr1_mask;
+        break;
+    case PEGPL_OMR2BAH:
+        ret = state->omr2_base >> 32;
+        break;
+    case PEGPL_OMR2BAL:
+        ret = state->omr2_base;
+        break;
+    case PEGPL_OMR2MSKH:
+        ret = state->omr2_mask >> 32;
+        break;
+    case PEGPL_OMR2MSKL:
+        ret = state->omr3_mask;
+        break;
+    case PEGPL_OMR3BAH:
+        ret = state->omr3_base >> 32;
+        break;
+    case PEGPL_OMR3BAL:
+        ret = state->omr3_base;
+        break;
+    case PEGPL_OMR3MSKH:
+        ret = state->omr3_mask >> 32;
+        break;
+    case PEGPL_OMR3MSKL:
+        ret = state->omr3_mask;
+        break;
+    case PEGPL_REGBAH:
+        ret = state->reg_base >> 32;
+        break;
+    case PEGPL_REGBAL:
+        ret = state->reg_base;
+        break;
+    case PEGPL_REGMSK:
+        ret = state->reg_mask;
+        break;
+    case PEGPL_SPECIAL:
+        ret = state->special;
+        break;
+    case PEGPL_CFG:
+        ret = state->cfg;
+        break;
+    }
+
+    return ret;
+}
+
+static void dcr_write_pcie(void *opaque, int dcrn, uint32_t val)
+{
+    PPC460EXPCIEState *s = opaque;
+    uint64_t size;
+
+    switch (dcrn - s->dcrn_base) {
+    case PEGPL_CFGBAH:
+        s->cfg_base = ((uint64_t)val << 32) | (s->cfg_base & 0xffffffff);
+        break;
+    case PEGPL_CFGBAL:
+        s->cfg_base = (s->cfg_base & 0xffffffff00000000ULL) | val;
+        break;
+    case PEGPL_CFGMSK:
+        s->cfg_mask = val;
+        size = ~(val & 0xfffffffe) + 1;
+        qemu_mutex_lock_iothread();
+        pcie_host_mmcfg_update(PCIE_HOST_BRIDGE(s), val & 1, s->cfg_base, size);
+        qemu_mutex_unlock_iothread();
+        break;
+    case PEGPL_MSGBAH:
+        s->msg_base = ((uint64_t)val << 32) | (s->msg_base & 0xffffffff);
+        break;
+    case PEGPL_MSGBAL:
+        s->msg_base = (s->msg_base & 0xffffffff00000000ULL) | val;
+        break;
+    case PEGPL_MSGMSK:
+        s->msg_mask = val;
+        break;
+    case PEGPL_OMR1BAH:
+        s->omr1_base = ((uint64_t)val << 32) | (s->omr1_base & 0xffffffff);
+        break;
+    case PEGPL_OMR1BAL:
+        s->omr1_base = (s->omr1_base & 0xffffffff00000000ULL) | val;
+        break;
+    case PEGPL_OMR1MSKH:
+        s->omr1_mask = ((uint64_t)val << 32) | (s->omr1_mask & 0xffffffff);
+        break;
+    case PEGPL_OMR1MSKL:
+        s->omr1_mask = (s->omr1_mask & 0xffffffff00000000ULL) | val;
+        break;
+    case PEGPL_OMR2BAH:
+        s->omr2_base = ((uint64_t)val << 32) | (s->omr2_base & 0xffffffff);
+        break;
+    case PEGPL_OMR2BAL:
+        s->omr2_base = (s->omr2_base & 0xffffffff00000000ULL) | val;
+        break;
+    case PEGPL_OMR2MSKH:
+        s->omr2_mask = ((uint64_t)val << 32) | (s->omr2_mask & 0xffffffff);
+        break;
+    case PEGPL_OMR2MSKL:
+        s->omr2_mask = (s->omr2_mask & 0xffffffff00000000ULL) | val;
+        break;
+    case PEGPL_OMR3BAH:
+        s->omr3_base = ((uint64_t)val << 32) | (s->omr3_base & 0xffffffff);
+        break;
+    case PEGPL_OMR3BAL:
+        s->omr3_base = (s->omr3_base & 0xffffffff00000000ULL) | val;
+        break;
+    case PEGPL_OMR3MSKH:
+        s->omr3_mask = ((uint64_t)val << 32) | (s->omr3_mask & 0xffffffff);
+        break;
+    case PEGPL_OMR3MSKL:
+        s->omr3_mask = (s->omr3_mask & 0xffffffff00000000ULL) | val;
+        break;
+    case PEGPL_REGBAH:
+        s->reg_base = ((uint64_t)val << 32) | (s->reg_base & 0xffffffff);
+        break;
+    case PEGPL_REGBAL:
+        s->reg_base = (s->reg_base & 0xffffffff00000000ULL) | val;
+        break;
+    case PEGPL_REGMSK:
+        s->reg_mask = val;
+        /* FIXME: how is size encoded? */
+        size = (val == 0x7001 ? 4096 : ~(val & 0xfffffffe) + 1);
+        break;
+    case PEGPL_SPECIAL:
+        s->special = val;
+        break;
+    case PEGPL_CFG:
+        s->cfg = val;
+        break;
+    }
+}
+
+static void ppc460ex_set_irq(void *opaque, int irq_num, int level)
+{
+       PPC460EXPCIEState *s = opaque;
+       qemu_set_irq(s->irq[irq_num], level);
+}
+
+static void ppc460ex_pcie_realize(DeviceState *dev, Error **errp)
+{
+    PPC460EXPCIEState *s = PPC460EX_PCIE_HOST(dev);
+    PCIHostState *pci = PCI_HOST_BRIDGE(dev);
+    int i, id;
+    char buf[16];
+
+    switch (s->dcrn_base) {
+    case DCRN_PCIE0_BASE:
+        id = 0;
+        break;
+    case DCRN_PCIE1_BASE:
+        id = 1;
+        break;
+    }
+    snprintf(buf, sizeof(buf), "pcie%d-io", id);
+    memory_region_init(&s->iomem, OBJECT(s), buf, UINT64_MAX);
+    for (i = 0; i < 4; i++) {
+        sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[i]);
+    }
+    snprintf(buf, sizeof(buf), "pcie.%d", id);
+    pci->bus = pci_register_root_bus(DEVICE(s), buf, ppc460ex_set_irq,
+                                pci_swizzle_map_irq_fn, s, &s->iomem,
+                                get_system_io(), 0, 4, TYPE_PCIE_BUS);
+}
+
+static Property ppc460ex_pcie_props[] = {
+    DEFINE_PROP_INT32("dcrn-base", PPC460EXPCIEState, dcrn_base, -1),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ppc460ex_pcie_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
+    dc->realize = ppc460ex_pcie_realize;
+    dc->props = ppc460ex_pcie_props;
+    dc->hotpluggable = false;
+}
+
+static const TypeInfo ppc460ex_pcie_host_info = {
+    .name = TYPE_PPC460EX_PCIE_HOST,
+    .parent = TYPE_PCIE_HOST_BRIDGE,
+    .instance_size = sizeof(PPC460EXPCIEState),
+    .class_init = ppc460ex_pcie_class_init,
+};
+
+static void ppc460ex_pcie_register(void)
+{
+    type_register_static(&ppc460ex_pcie_host_info);
+}
+
+type_init(ppc460ex_pcie_register)
+
+static void ppc460ex_pcie_register_dcrs(PPC460EXPCIEState *s, CPUPPCState *env)
+{
+    ppc_dcr_register(env, s->dcrn_base + PEGPL_CFGBAH, s,
+                     &dcr_read_pcie, &dcr_write_pcie);
+    ppc_dcr_register(env, s->dcrn_base + PEGPL_CFGBAL, s,
+                     &dcr_read_pcie, &dcr_write_pcie);
+    ppc_dcr_register(env, s->dcrn_base + PEGPL_CFGMSK, s,
+                     &dcr_read_pcie, &dcr_write_pcie);
+    ppc_dcr_register(env, s->dcrn_base + PEGPL_MSGBAH, s,
+                     &dcr_read_pcie, &dcr_write_pcie);
+    ppc_dcr_register(env, s->dcrn_base + PEGPL_MSGBAL, s,
+                     &dcr_read_pcie, &dcr_write_pcie);
+    ppc_dcr_register(env, s->dcrn_base + PEGPL_MSGMSK, s,
+                     &dcr_read_pcie, &dcr_write_pcie);
+    ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR1BAH, s,
+                     &dcr_read_pcie, &dcr_write_pcie);
+    ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR1BAL, s,
+                     &dcr_read_pcie, &dcr_write_pcie);
+    ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR1MSKH, s,
+                     &dcr_read_pcie, &dcr_write_pcie);
+    ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR1MSKL, s,
+                     &dcr_read_pcie, &dcr_write_pcie);
+    ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR2BAH, s,
+                     &dcr_read_pcie, &dcr_write_pcie);
+    ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR2BAL, s,
+                     &dcr_read_pcie, &dcr_write_pcie);
+    ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR2MSKH, s,
+                     &dcr_read_pcie, &dcr_write_pcie);
+    ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR2MSKL, s,
+                     &dcr_read_pcie, &dcr_write_pcie);
+    ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR3BAH, s,
+                     &dcr_read_pcie, &dcr_write_pcie);
+    ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR3BAL, s,
+                     &dcr_read_pcie, &dcr_write_pcie);
+    ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR3MSKH, s,
+                     &dcr_read_pcie, &dcr_write_pcie);
+    ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR3MSKL, s,
+                     &dcr_read_pcie, &dcr_write_pcie);
+    ppc_dcr_register(env, s->dcrn_base + PEGPL_REGBAH, s,
+                     &dcr_read_pcie, &dcr_write_pcie);
+    ppc_dcr_register(env, s->dcrn_base + PEGPL_REGBAL, s,
+                     &dcr_read_pcie, &dcr_write_pcie);
+    ppc_dcr_register(env, s->dcrn_base + PEGPL_REGMSK, s,
+                     &dcr_read_pcie, &dcr_write_pcie);
+    ppc_dcr_register(env, s->dcrn_base + PEGPL_SPECIAL, s,
+                     &dcr_read_pcie, &dcr_write_pcie);
+    ppc_dcr_register(env, s->dcrn_base + PEGPL_CFG, s,
+                     &dcr_read_pcie, &dcr_write_pcie);
+}
+
+void ppc460ex_pcie_init(CPUPPCState *env)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, TYPE_PPC460EX_PCIE_HOST);
+    qdev_prop_set_int32(dev, "dcrn-base", DCRN_PCIE0_BASE);
+    qdev_init_nofail(dev);
+    object_property_set_bool(OBJECT(dev), true, "realized", NULL);
+    ppc460ex_pcie_register_dcrs(PPC460EX_PCIE_HOST(dev), env);
+
+    dev = qdev_create(NULL, TYPE_PPC460EX_PCIE_HOST);
+    qdev_prop_set_int32(dev, "dcrn-base", DCRN_PCIE1_BASE);
+    qdev_init_nofail(dev);
+    object_property_set_bool(OBJECT(dev), true, "realized", NULL);
+    ppc460ex_pcie_register_dcrs(PPC460EX_PCIE_HOST(dev), env);
+}
diff --git a/include/hw/pci/pcie_host.h b/include/hw/pci/pcie_host.h
index 4d23c80..3f7b988 100644
--- a/include/hw/pci/pcie_host.h
+++ b/include/hw/pci/pcie_host.h
@@ -65,7 +65,7 @@ void pcie_host_mmcfg_update(PCIExpressHost *e,
  * bit 12 - 14: function number
  * bit  0 - 11: offset in configuration space of a given device
  */
-#define PCIE_MMCFG_SIZE_MAX             (1ULL << 28)
+#define PCIE_MMCFG_SIZE_MAX             (1ULL << 29)
 #define PCIE_MMCFG_SIZE_MIN             (1ULL << 20)
 #define PCIE_MMCFG_BUS_BIT              20
 #define PCIE_MMCFG_BUS_MASK             0x1ff
-- 
2.7.6

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [PATCH v2 1/3] ppc4xx: Add device models found in PPC440 core SoCs
  2018-02-15 21:27 ` [Qemu-devel] [PATCH v2 1/3] ppc4xx: Add device models found in PPC440 core SoCs BALATON Zoltan
@ 2018-02-16  3:06   ` David Gibson
  0 siblings, 0 replies; 16+ messages in thread
From: David Gibson @ 2018-02-16  3:06 UTC (permalink / raw)
  To: BALATON Zoltan; +Cc: qemu-devel, qemu-ppc, Alexander Graf, Francois Revol

[-- Attachment #1: Type: text/plain, Size: 39991 bytes --]

On Thu, Feb 15, 2018 at 10:27:06PM +0100, BALATON Zoltan wrote:
> These devices are found in newer SoCs based on 440 core e.g. the 460EX
> (http://www.embeddeddeveloper.com/assets/processors/amcc/datasheets/
> PP460EX_DS2063.pdf)
> 
> Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>

Applied, thanks.

> ---
> 
> v2:
> - Rebased to latest changes on master
> - Removed printfs
> 
>  hw/ppc/ppc440.h            |   26 +
>  hw/ppc/ppc440_uc.c         | 1159 ++++++++++++++++++++++++++++++++++++++++++++
>  include/hw/pci/pcie_host.h |    2 +-
>  3 files changed, 1186 insertions(+), 1 deletion(-)
>  create mode 100644 hw/ppc/ppc440.h
>  create mode 100644 hw/ppc/ppc440_uc.c
> 
> diff --git a/hw/ppc/ppc440.h b/hw/ppc/ppc440.h
> new file mode 100644
> index 0000000..ad27db1
> --- /dev/null
> +++ b/hw/ppc/ppc440.h
> @@ -0,0 +1,26 @@
> +/*
> + * QEMU PowerPC 440 shared definitions
> + *
> + * Copyright (c) 2012 François Revol
> + * Copyright (c) 2016-2018 BALATON Zoltan
> + *
> + * This work is licensed under the GNU GPL license version 2 or later.
> + *
> + */
> +
> +#ifndef PPC440_H
> +#define PPC440_H
> +
> +#include "hw/ppc/ppc.h"
> +
> +void ppc4xx_l2sram_init(CPUPPCState *env);
> +void ppc4xx_cpr_init(CPUPPCState *env);
> +void ppc4xx_sdr_init(CPUPPCState *env);
> +void ppc440_sdram_init(CPUPPCState *env, int nbanks,
> +                       MemoryRegion *ram_memories,
> +                       hwaddr *ram_bases, hwaddr *ram_sizes,
> +                       int do_init);
> +void ppc4xx_ahb_init(CPUPPCState *env);
> +void ppc460ex_pcie_init(CPUPPCState *env);
> +
> +#endif /* PPC440_H */
> diff --git a/hw/ppc/ppc440_uc.c b/hw/ppc/ppc440_uc.c
> new file mode 100644
> index 0000000..4e2523a
> --- /dev/null
> +++ b/hw/ppc/ppc440_uc.c
> @@ -0,0 +1,1159 @@
> +/*
> + * QEMU PowerPC 440 embedded processors emulation
> + *
> + * Copyright (c) 2012 François Revol
> + * Copyright (c) 2016-2018 BALATON Zoltan
> + *
> + * This work is licensed under the GNU GPL license version 2 or later.
> + *
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qemu-common.h"
> +#include "qemu/cutils.h"
> +#include "qemu/error-report.h"
> +#include "qapi/error.h"
> +#include "cpu.h"
> +#include "hw/hw.h"
> +#include "exec/address-spaces.h"
> +#include "exec/memory.h"
> +#include "hw/ppc/ppc.h"
> +#include "hw/pci/pci.h"
> +#include "sysemu/block-backend.h"
> +#include "hw/ppc/ppc440.h"
> +
> +/*****************************************************************************/
> +/* L2 Cache as SRAM */
> +/* FIXME:fix names */
> +enum {
> +    DCR_L2CACHE_BASE  = 0x30,
> +    DCR_L2CACHE_CFG   = DCR_L2CACHE_BASE,
> +    DCR_L2CACHE_CMD,
> +    DCR_L2CACHE_ADDR,
> +    DCR_L2CACHE_DATA,
> +    DCR_L2CACHE_STAT,
> +    DCR_L2CACHE_CVER,
> +    DCR_L2CACHE_SNP0,
> +    DCR_L2CACHE_SNP1,
> +    DCR_L2CACHE_END   = DCR_L2CACHE_SNP1,
> +};
> +
> +/* base is 460ex-specific, cf. U-Boot, ppc4xx-isram.h */
> +enum {
> +    DCR_ISRAM0_BASE   = 0x20,
> +    DCR_ISRAM0_SB0CR  = DCR_ISRAM0_BASE,
> +    DCR_ISRAM0_SB1CR,
> +    DCR_ISRAM0_SB2CR,
> +    DCR_ISRAM0_SB3CR,
> +    DCR_ISRAM0_BEAR,
> +    DCR_ISRAM0_BESR0,
> +    DCR_ISRAM0_BESR1,
> +    DCR_ISRAM0_PMEG,
> +    DCR_ISRAM0_CID,
> +    DCR_ISRAM0_REVID,
> +    DCR_ISRAM0_DPC,
> +    DCR_ISRAM0_END    = DCR_ISRAM0_DPC
> +};
> +
> +enum {
> +    DCR_ISRAM1_BASE   = 0xb0,
> +    DCR_ISRAM1_SB0CR  = DCR_ISRAM1_BASE,
> +    /* single bank */
> +    DCR_ISRAM1_BEAR   = DCR_ISRAM1_BASE + 0x04,
> +    DCR_ISRAM1_BESR0,
> +    DCR_ISRAM1_BESR1,
> +    DCR_ISRAM1_PMEG,
> +    DCR_ISRAM1_CID,
> +    DCR_ISRAM1_REVID,
> +    DCR_ISRAM1_DPC,
> +    DCR_ISRAM1_END    = DCR_ISRAM1_DPC
> +};
> +
> +typedef struct ppc4xx_l2sram_t {
> +    MemoryRegion bank[4];
> +    uint32_t l2cache[8];
> +    uint32_t isram0[11];
> +} ppc4xx_l2sram_t;
> +
> +#ifdef MAP_L2SRAM
> +static void l2sram_update_mappings(ppc4xx_l2sram_t *l2sram,
> +                                   uint32_t isarc, uint32_t isacntl,
> +                                   uint32_t dsarc, uint32_t dsacntl)
> +{
> +    if (l2sram->isarc != isarc ||
> +        (l2sram->isacntl & 0x80000000) != (isacntl & 0x80000000)) {
> +        if (l2sram->isacntl & 0x80000000) {
> +            /* Unmap previously assigned memory region */
> +            memory_region_del_subregion(get_system_memory(),
> +                                        &l2sram->isarc_ram);
> +        }
> +        if (isacntl & 0x80000000) {
> +            /* Map new instruction memory region */
> +            memory_region_add_subregion(get_system_memory(), isarc,
> +                                        &l2sram->isarc_ram);
> +        }
> +    }
> +    if (l2sram->dsarc != dsarc ||
> +        (l2sram->dsacntl & 0x80000000) != (dsacntl & 0x80000000)) {
> +        if (l2sram->dsacntl & 0x80000000) {
> +            /* Beware not to unmap the region we just mapped */
> +            if (!(isacntl & 0x80000000) || l2sram->dsarc != isarc) {
> +                /* Unmap previously assigned memory region */
> +                memory_region_del_subregion(get_system_memory(),
> +                                            &l2sram->dsarc_ram);
> +            }
> +        }
> +        if (dsacntl & 0x80000000) {
> +            /* Beware not to remap the region we just mapped */
> +            if (!(isacntl & 0x80000000) || dsarc != isarc) {
> +                /* Map new data memory region */
> +                memory_region_add_subregion(get_system_memory(), dsarc,
> +                                            &l2sram->dsarc_ram);
> +            }
> +        }
> +    }
> +}
> +#endif
> +
> +static uint32_t dcr_read_l2sram(void *opaque, int dcrn)
> +{
> +    ppc4xx_l2sram_t *l2sram = opaque;
> +    uint32_t ret = 0;
> +
> +    switch (dcrn) {
> +    case DCR_L2CACHE_CFG:
> +    case DCR_L2CACHE_CMD:
> +    case DCR_L2CACHE_ADDR:
> +    case DCR_L2CACHE_DATA:
> +    case DCR_L2CACHE_STAT:
> +    case DCR_L2CACHE_CVER:
> +    case DCR_L2CACHE_SNP0:
> +    case DCR_L2CACHE_SNP1:
> +        ret = l2sram->l2cache[dcrn - DCR_L2CACHE_BASE];
> +        break;
> +
> +    case DCR_ISRAM0_SB0CR:
> +    case DCR_ISRAM0_SB1CR:
> +    case DCR_ISRAM0_SB2CR:
> +    case DCR_ISRAM0_SB3CR:
> +    case DCR_ISRAM0_BEAR:
> +    case DCR_ISRAM0_BESR0:
> +    case DCR_ISRAM0_BESR1:
> +    case DCR_ISRAM0_PMEG:
> +    case DCR_ISRAM0_CID:
> +    case DCR_ISRAM0_REVID:
> +    case DCR_ISRAM0_DPC:
> +        ret = l2sram->isram0[dcrn - DCR_ISRAM0_BASE];
> +        break;
> +
> +    default:
> +        break;
> +    }
> +
> +    return ret;
> +}
> +
> +static void dcr_write_l2sram(void *opaque, int dcrn, uint32_t val)
> +{
> +    /*ppc4xx_l2sram_t *l2sram = opaque;*/
> +    /* FIXME: Actually handle L2 cache mapping */
> +
> +    switch (dcrn) {
> +    case DCR_L2CACHE_CFG:
> +    case DCR_L2CACHE_CMD:
> +    case DCR_L2CACHE_ADDR:
> +    case DCR_L2CACHE_DATA:
> +    case DCR_L2CACHE_STAT:
> +    case DCR_L2CACHE_CVER:
> +    case DCR_L2CACHE_SNP0:
> +    case DCR_L2CACHE_SNP1:
> +        /*l2sram->l2cache[dcrn - DCR_L2CACHE_BASE] = val;*/
> +        break;
> +
> +    case DCR_ISRAM0_SB0CR:
> +    case DCR_ISRAM0_SB1CR:
> +    case DCR_ISRAM0_SB2CR:
> +    case DCR_ISRAM0_SB3CR:
> +    case DCR_ISRAM0_BEAR:
> +    case DCR_ISRAM0_BESR0:
> +    case DCR_ISRAM0_BESR1:
> +    case DCR_ISRAM0_PMEG:
> +    case DCR_ISRAM0_CID:
> +    case DCR_ISRAM0_REVID:
> +    case DCR_ISRAM0_DPC:
> +        /*l2sram->isram0[dcrn - DCR_L2CACHE_BASE] = val;*/
> +        break;
> +
> +    case DCR_ISRAM1_SB0CR:
> +    case DCR_ISRAM1_BEAR:
> +    case DCR_ISRAM1_BESR0:
> +    case DCR_ISRAM1_BESR1:
> +    case DCR_ISRAM1_PMEG:
> +    case DCR_ISRAM1_CID:
> +    case DCR_ISRAM1_REVID:
> +    case DCR_ISRAM1_DPC:
> +        /*l2sram->isram1[dcrn - DCR_L2CACHE_BASE] = val;*/
> +        break;
> +    }
> +    /*l2sram_update_mappings(l2sram, isarc, isacntl, dsarc, dsacntl);*/
> +}
> +
> +static void l2sram_reset(void *opaque)
> +{
> +    ppc4xx_l2sram_t *l2sram = opaque;
> +
> +    memset(l2sram->l2cache, 0, sizeof(l2sram->l2cache));
> +    l2sram->l2cache[DCR_L2CACHE_STAT - DCR_L2CACHE_BASE] = 0x80000000;
> +    memset(l2sram->isram0, 0, sizeof(l2sram->isram0));
> +    /*l2sram_update_mappings(l2sram, isarc, isacntl, dsarc, dsacntl);*/
> +}
> +
> +void ppc4xx_l2sram_init(CPUPPCState *env)
> +{
> +    ppc4xx_l2sram_t *l2sram;
> +
> +    l2sram = g_malloc0(sizeof(*l2sram));
> +    /* XXX: Size is 4*64kB for 460ex, cf. U-Boot, ppc4xx-isram.h */
> +    memory_region_init_ram(&l2sram->bank[0], NULL, "ppc4xx.l2sram_bank0",
> +                           64 * K_BYTE, &error_abort);
> +    memory_region_init_ram(&l2sram->bank[1], NULL, "ppc4xx.l2sram_bank1",
> +                           64 * K_BYTE, &error_abort);
> +    memory_region_init_ram(&l2sram->bank[2], NULL, "ppc4xx.l2sram_bank2",
> +                           64 * K_BYTE, &error_abort);
> +    memory_region_init_ram(&l2sram->bank[3], NULL, "ppc4xx.l2sram_bank3",
> +                           64 * K_BYTE, &error_abort);
> +    qemu_register_reset(&l2sram_reset, l2sram);
> +    ppc_dcr_register(env, DCR_L2CACHE_CFG,
> +                     l2sram, &dcr_read_l2sram, &dcr_write_l2sram);
> +    ppc_dcr_register(env, DCR_L2CACHE_CMD,
> +                     l2sram, &dcr_read_l2sram, &dcr_write_l2sram);
> +    ppc_dcr_register(env, DCR_L2CACHE_ADDR,
> +                     l2sram, &dcr_read_l2sram, &dcr_write_l2sram);
> +    ppc_dcr_register(env, DCR_L2CACHE_DATA,
> +                     l2sram, &dcr_read_l2sram, &dcr_write_l2sram);
> +    ppc_dcr_register(env, DCR_L2CACHE_STAT,
> +                     l2sram, &dcr_read_l2sram, &dcr_write_l2sram);
> +    ppc_dcr_register(env, DCR_L2CACHE_CVER,
> +                     l2sram, &dcr_read_l2sram, &dcr_write_l2sram);
> +    ppc_dcr_register(env, DCR_L2CACHE_SNP0,
> +                     l2sram, &dcr_read_l2sram, &dcr_write_l2sram);
> +    ppc_dcr_register(env, DCR_L2CACHE_SNP1,
> +                     l2sram, &dcr_read_l2sram, &dcr_write_l2sram);
> +
> +    ppc_dcr_register(env, DCR_ISRAM0_SB0CR,
> +                     l2sram, &dcr_read_l2sram, &dcr_write_l2sram);
> +    ppc_dcr_register(env, DCR_ISRAM0_SB1CR,
> +                     l2sram, &dcr_read_l2sram, &dcr_write_l2sram);
> +    ppc_dcr_register(env, DCR_ISRAM0_SB2CR,
> +                     l2sram, &dcr_read_l2sram, &dcr_write_l2sram);
> +    ppc_dcr_register(env, DCR_ISRAM0_SB3CR,
> +                     l2sram, &dcr_read_l2sram, &dcr_write_l2sram);
> +    ppc_dcr_register(env, DCR_ISRAM0_PMEG,
> +                     l2sram, &dcr_read_l2sram, &dcr_write_l2sram);
> +    ppc_dcr_register(env, DCR_ISRAM0_DPC,
> +                     l2sram, &dcr_read_l2sram, &dcr_write_l2sram);
> +
> +    ppc_dcr_register(env, DCR_ISRAM1_SB0CR,
> +                     l2sram, &dcr_read_l2sram, &dcr_write_l2sram);
> +    ppc_dcr_register(env, DCR_ISRAM1_PMEG,
> +                     l2sram, &dcr_read_l2sram, &dcr_write_l2sram);
> +    ppc_dcr_register(env, DCR_ISRAM1_DPC,
> +                     l2sram, &dcr_read_l2sram, &dcr_write_l2sram);
> +}
> +
> +/*****************************************************************************/
> +/* Clocking Power on Reset */
> +enum {
> +    CPR0_CFGADDR = 0xC,
> +    CPR0_CFGDATA = 0xD,
> +
> +    CPR0_PLLD = 0x060,
> +    CPR0_PLBED = 0x080,
> +    CPR0_OPBD = 0x0C0,
> +    CPR0_PERD = 0x0E0,
> +    CPR0_AHBD = 0x100,
> +};
> +
> +typedef struct ppc4xx_cpr_t {
> +    uint32_t addr;
> +} ppc4xx_cpr_t;
> +
> +static uint32_t dcr_read_cpr(void *opaque, int dcrn)
> +{
> +    ppc4xx_cpr_t *cpr = opaque;
> +    uint32_t ret = 0;
> +
> +    switch (dcrn) {
> +    case CPR0_CFGADDR:
> +        ret = cpr->addr;
> +        break;
> +    case CPR0_CFGDATA:
> +        switch (cpr->addr) {
> +        case CPR0_PLLD:
> +            ret = (0xb5 << 24) | (1 << 16) | (9 << 8);
> +            break;
> +        case CPR0_PLBED:
> +            ret = (5 << 24);
> +            break;
> +        case CPR0_OPBD:
> +            ret = (2 << 24);
> +            break;
> +        case CPR0_PERD:
> +        case CPR0_AHBD:
> +            ret = (1 << 24);
> +            break;
> +        default:
> +            break;
> +        }
> +        break;
> +    default:
> +        break;
> +    }
> +
> +    return ret;
> +}
> +
> +static void dcr_write_cpr(void *opaque, int dcrn, uint32_t val)
> +{
> +    ppc4xx_cpr_t *cpr = opaque;
> +
> +    switch (dcrn) {
> +    case CPR0_CFGADDR:
> +        cpr->addr = val;
> +        break;
> +    case CPR0_CFGDATA:
> +        break;
> +    default:
> +        break;
> +    }
> +}
> +
> +static void ppc4xx_cpr_reset(void *opaque)
> +{
> +    ppc4xx_cpr_t *cpr = opaque;
> +
> +    cpr->addr = 0;
> +}
> +
> +void ppc4xx_cpr_init(CPUPPCState *env)
> +{
> +    ppc4xx_cpr_t *cpr;
> +
> +    cpr = g_malloc0(sizeof(*cpr));
> +    ppc_dcr_register(env, CPR0_CFGADDR, cpr, &dcr_read_cpr, &dcr_write_cpr);
> +    ppc_dcr_register(env, CPR0_CFGDATA, cpr, &dcr_read_cpr, &dcr_write_cpr);
> +    qemu_register_reset(ppc4xx_cpr_reset, cpr);
> +}
> +
> +/*****************************************************************************/
> +/* System DCRs */
> +typedef struct ppc4xx_sdr_t ppc4xx_sdr_t;
> +struct ppc4xx_sdr_t {
> +    uint32_t addr;
> +};
> +
> +enum {
> +    SDR0_CFGADDR = 0x00e,
> +    SDR0_CFGDATA,
> +    SDR0_STRP0 = 0x020,
> +    SDR0_STRP1,
> +    SDR0_102 = 0x66,
> +    SDR0_103,
> +    SDR0_128 = 0x80,
> +    SDR0_ECID3 = 0x083,
> +    SDR0_DDR0 = 0x0e1,
> +    SDR0_USB0 = 0x320,
> +};
> +
> +enum {
> +    PESDR0_LOOP = 0x303,
> +    PESDR0_RCSSET,
> +    PESDR0_RCSSTS,
> +    PESDR0_RSTSTA = 0x310,
> +    PESDR1_LOOP = 0x343,
> +    PESDR1_RCSSET,
> +    PESDR1_RCSSTS,
> +    PESDR1_RSTSTA = 0x365,
> +};
> +
> +#define SDR0_DDR0_DDRM_ENCODE(n)  ((((unsigned long)(n)) & 0x03) << 29)
> +#define SDR0_DDR0_DDRM_DDR1       0x20000000
> +#define SDR0_DDR0_DDRM_DDR2       0x40000000
> +
> +static uint32_t dcr_read_sdr(void *opaque, int dcrn)
> +{
> +    ppc4xx_sdr_t *sdr = opaque;
> +    uint32_t ret = 0;
> +
> +    switch (dcrn) {
> +    case SDR0_CFGADDR:
> +        ret = sdr->addr;
> +        break;
> +    case SDR0_CFGDATA:
> +        switch (sdr->addr) {
> +        case SDR0_STRP0:
> +            /* FIXME: Is this correct? This breaks timing in U-Boot */
> +            ret = 0; /*(0xb5 << 8) | (1 << 4) | 9 */
> +            break;
> +        case SDR0_STRP1:
> +            ret = (5 << 29) | (2 << 26) | (1 << 24);
> +            break;
> +        case SDR0_ECID3:
> +            ret = 1 << 20; /* No Security/Kasumi support */
> +            break;
> +        case SDR0_DDR0:
> +            ret = SDR0_DDR0_DDRM_ENCODE(1) | SDR0_DDR0_DDRM_DDR1;
> +            break;
> +        case PESDR0_RCSSET:
> +        case PESDR1_RCSSET:
> +            ret = (1 << 24) | (1 << 16);
> +            break;
> +        case PESDR0_RCSSTS:
> +        case PESDR1_RCSSTS:
> +            ret = (1 << 16) | (1 << 12);
> +            break;
> +        case PESDR0_RSTSTA:
> +        case PESDR1_RSTSTA:
> +            ret = 1;
> +            break;
> +        case PESDR0_LOOP:
> +        case PESDR1_LOOP:
> +            ret = 1 << 12;
> +            break;
> +        default:
> +            break;
> +        }
> +        break;
> +    default:
> +        break;
> +    }
> +
> +    return ret;
> +}
> +
> +static void dcr_write_sdr(void *opaque, int dcrn, uint32_t val)
> +{
> +    ppc4xx_sdr_t *sdr = opaque;
> +
> +    switch (dcrn) {
> +    case SDR0_CFGADDR:
> +        sdr->addr = val;
> +        break;
> +    case SDR0_CFGDATA:
> +        switch (sdr->addr) {
> +        case 0x00: /* B0CR */
> +            break;
> +        default:
> +            break;
> +        }
> +        break;
> +    default:
> +        break;
> +    }
> +}
> +
> +static void sdr_reset(void *opaque)
> +{
> +    ppc4xx_sdr_t *sdr = opaque;
> +
> +    sdr->addr = 0;
> +}
> +
> +void ppc4xx_sdr_init(CPUPPCState *env)
> +{
> +    ppc4xx_sdr_t *sdr;
> +
> +    sdr = g_malloc0(sizeof(*sdr));
> +    qemu_register_reset(&sdr_reset, sdr);
> +    ppc_dcr_register(env, SDR0_CFGADDR,
> +                     sdr, &dcr_read_sdr, &dcr_write_sdr);
> +    ppc_dcr_register(env, SDR0_CFGDATA,
> +                     sdr, &dcr_read_sdr, &dcr_write_sdr);
> +    ppc_dcr_register(env, SDR0_102,
> +                     sdr, &dcr_read_sdr, &dcr_write_sdr);
> +    ppc_dcr_register(env, SDR0_103,
> +                     sdr, &dcr_read_sdr, &dcr_write_sdr);
> +    ppc_dcr_register(env, SDR0_128,
> +                     sdr, &dcr_read_sdr, &dcr_write_sdr);
> +    ppc_dcr_register(env, SDR0_USB0,
> +                     sdr, &dcr_read_sdr, &dcr_write_sdr);
> +}
> +
> +/*****************************************************************************/
> +/* SDRAM controller */
> +typedef 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 bcr[4];
> +} ppc4xx_sdram_t;
> +
> +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,
> +};
> +
> +/* 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_bcr(hwaddr ram_base, hwaddr ram_size)
> +{
> +    uint32_t bcr;
> +
> +    switch (ram_size) {
> +    case (8 * M_BYTE):
> +        bcr = 0xffc0;
> +        break;
> +    case (16 * M_BYTE):
> +        bcr = 0xff80;
> +        break;
> +    case (32 * M_BYTE):
> +        bcr = 0xff00;
> +        break;
> +    case (64 * M_BYTE):
> +        bcr = 0xfe00;
> +        break;
> +    case (128 * M_BYTE):
> +        bcr = 0xfc00;
> +        break;
> +    case (256 * M_BYTE):
> +        bcr = 0xf800;
> +        break;
> +    case (512 * M_BYTE):
> +        bcr = 0xf000;
> +        break;
> +    case (1 * G_BYTE):
> +        bcr = 0xe000;
> +        break;
> +    default:
> +        error_report("invalid RAM size " TARGET_FMT_plx, ram_size);
> +        return 0;
> +    }
> +    bcr |= ram_base & 0xFF800000;
> +    bcr |= 1;
> +
> +    return bcr;
> +}
> +
> +static inline hwaddr sdram_base(uint32_t bcr)
> +{
> +    return bcr & 0xFF800000;
> +}
> +
> +static target_ulong sdram_size(uint32_t bcr)
> +{
> +    target_ulong size;
> +    int sh;
> +
> +    sh = 1024 - ((bcr >> 6) & 0x3ff);
> +    if (sh == 0) {
> +        size = -1;
> +    } else {
> +        size = 8 * M_BYTE * sh;
> +    }
> +
> +    return size;
> +}
> +
> +static void sdram_set_bcr(ppc4xx_sdram_t *sdram,
> +                          uint32_t *bcrp, uint32_t bcr, int enabled)
> +{
> +    unsigned n = bcrp - sdram->bcr;
> +
> +    if (*bcrp & 1) {
> +        /* Unmap RAM */
> +        memory_region_del_subregion(get_system_memory(),
> +                                    &sdram->containers[n]);
> +        memory_region_del_subregion(&sdram->containers[n],
> +                                    &sdram->ram_memories[n]);
> +        object_unparent(OBJECT(&sdram->containers[n]));
> +    }
> +    *bcrp = bcr & 0xFFDEE001;
> +    if (enabled && (bcr & 1)) {
> +        memory_region_init(&sdram->containers[n], NULL, "sdram-containers",
> +                           sdram_size(bcr));
> +        memory_region_add_subregion(&sdram->containers[n], 0,
> +                                    &sdram->ram_memories[n]);
> +        memory_region_add_subregion(get_system_memory(),
> +                                    sdram_base(bcr),
> +                                    &sdram->containers[n]);
> +    }
> +}
> +
> +static void sdram_map_bcr(ppc4xx_sdram_t *sdram)
> +{
> +    int i;
> +
> +    for (i = 0; i < sdram->nbanks; i++) {
> +        if (sdram->ram_sizes[i] != 0) {
> +            sdram_set_bcr(sdram,
> +                          &sdram->bcr[i],
> +                          sdram_bcr(sdram->ram_bases[i], sdram->ram_sizes[i]),
> +                          1);
> +        } else {
> +            sdram_set_bcr(sdram, &sdram->bcr[i], 0, 0);
> +        }
> +    }
> +}
> +
> +static uint32_t dcr_read_sdram(void *opaque, int dcrn)
> +{
> +    ppc4xx_sdram_t *sdram = opaque;
> +    uint32_t ret = 0;
> +
> +    switch (dcrn) {
> +    case SDRAM_R0BAS:
> +    case SDRAM_R1BAS:
> +    case SDRAM_R2BAS:
> +    case SDRAM_R3BAS:
> +        ret = sdram_bcr(sdram->ram_bases[dcrn - SDRAM_R0BAS],
> +                        sdram->ram_sizes[dcrn - SDRAM_R0BAS]);
> +        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 = 0x08000000;
> +            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;
> +}
> +
> +static void dcr_write_sdram(void *opaque, int dcrn, uint32_t val)
> +{
> +    ppc4xx_sdram_t *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;
> +        default:
> +            break;
> +        }
> +        break;
> +    default:
> +        break;
> +    }
> +}
> +
> +static void sdram_reset(void *opaque)
> +{
> +    ppc4xx_sdram_t *sdram = opaque;
> +
> +    sdram->addr = 0;
> +}
> +
> +void ppc440_sdram_init(CPUPPCState *env, int nbanks,
> +                       MemoryRegion *ram_memories,
> +                       hwaddr *ram_bases, hwaddr *ram_sizes,
> +                       int do_init)
> +{
> +    ppc4xx_sdram_t *sdram;
> +
> +    sdram = g_malloc0(sizeof(*sdram));
> +    sdram->nbanks = nbanks;
> +    sdram->ram_memories = ram_memories;
> +    memcpy(sdram->ram_bases, ram_bases, nbanks * sizeof(hwaddr));
> +    memcpy(sdram->ram_sizes, ram_sizes, nbanks * sizeof(hwaddr));
> +    qemu_register_reset(&sdram_reset, sdram);
> +    ppc_dcr_register(env, SDRAM0_CFGADDR,
> +                     sdram, &dcr_read_sdram, &dcr_write_sdram);
> +    ppc_dcr_register(env, SDRAM0_CFGDATA,
> +                     sdram, &dcr_read_sdram, &dcr_write_sdram);
> +    if (do_init) {
> +        sdram_map_bcr(sdram);
> +    }
> +
> +    ppc_dcr_register(env, SDRAM_R0BAS,
> +                     sdram, &dcr_read_sdram, &dcr_write_sdram);
> +    ppc_dcr_register(env, SDRAM_R1BAS,
> +                     sdram, &dcr_read_sdram, &dcr_write_sdram);
> +    ppc_dcr_register(env, SDRAM_R2BAS,
> +                     sdram, &dcr_read_sdram, &dcr_write_sdram);
> +    ppc_dcr_register(env, SDRAM_R3BAS,
> +                     sdram, &dcr_read_sdram, &dcr_write_sdram);
> +    ppc_dcr_register(env, SDRAM_CONF1HB,
> +                     sdram, &dcr_read_sdram, &dcr_write_sdram);
> +    ppc_dcr_register(env, SDRAM_PLBADDULL,
> +                     sdram, &dcr_read_sdram, &dcr_write_sdram);
> +    ppc_dcr_register(env, SDRAM_CONF1LL,
> +                     sdram, &dcr_read_sdram, &dcr_write_sdram);
> +    ppc_dcr_register(env, SDRAM_CONFPATHB,
> +                     sdram, &dcr_read_sdram, &dcr_write_sdram);
> +    ppc_dcr_register(env, SDRAM_PLBADDUHB,
> +                     sdram, &dcr_read_sdram, &dcr_write_sdram);
> +}
> +
> +/*****************************************************************************/
> +/* PLB to AHB bridge */
> +enum {
> +    AHB_TOP    = 0xA4,
> +    AHB_BOT    = 0xA5,
> +};
> +
> +typedef struct ppc4xx_ahb_t {
> +    uint32_t top;
> +    uint32_t bot;
> +} ppc4xx_ahb_t;
> +
> +static uint32_t dcr_read_ahb(void *opaque, int dcrn)
> +{
> +    ppc4xx_ahb_t *ahb = opaque;
> +    uint32_t ret = 0;
> +
> +    switch (dcrn) {
> +    case AHB_TOP:
> +        ret = ahb->top;
> +        break;
> +    case AHB_BOT:
> +        ret = ahb->bot;
> +        break;
> +    default:
> +        break;
> +    }
> +
> +    return ret;
> +}
> +
> +static void dcr_write_ahb(void *opaque, int dcrn, uint32_t val)
> +{
> +    ppc4xx_ahb_t *ahb = opaque;
> +
> +    switch (dcrn) {
> +    case AHB_TOP:
> +        ahb->top = val;
> +        break;
> +    case AHB_BOT:
> +        ahb->bot = val;
> +        break;
> +    }
> +}
> +
> +static void ppc4xx_ahb_reset(void *opaque)
> +{
> +    ppc4xx_ahb_t *ahb = opaque;
> +
> +    /* No error */
> +    ahb->top = 0;
> +    ahb->bot = 0;
> +}
> +
> +void ppc4xx_ahb_init(CPUPPCState *env)
> +{
> +    ppc4xx_ahb_t *ahb;
> +
> +    ahb = g_malloc0(sizeof(*ahb));
> +    ppc_dcr_register(env, AHB_TOP, ahb, &dcr_read_ahb, &dcr_write_ahb);
> +    ppc_dcr_register(env, AHB_BOT, ahb, &dcr_read_ahb, &dcr_write_ahb);
> +    qemu_register_reset(ppc4xx_ahb_reset, ahb);
> +}
> +
> +/*****************************************************************************/
> +/* PCI Express controller */
> +/* FIXME: This is not complete and does not work, only implemented partially
> + * to allow firmware and guests to find an empty bus. Cards should use PCI.
> + */
> +#include "hw/pci/pcie_host.h"
> +
> +#define TYPE_PPC460EX_PCIE_HOST "ppc460ex-pcie-host"
> +#define PPC460EX_PCIE_HOST(obj) \
> +    OBJECT_CHECK(PPC460EXPCIEState, (obj), TYPE_PPC460EX_PCIE_HOST)
> +
> +typedef struct PPC460EXPCIEState {
> +    PCIExpressHost host;
> +
> +    MemoryRegion iomem;
> +    qemu_irq irq[4];
> +    int32_t dcrn_base;
> +
> +    uint64_t cfg_base;
> +    uint32_t cfg_mask;
> +    uint64_t msg_base;
> +    uint32_t msg_mask;
> +    uint64_t omr1_base;
> +    uint64_t omr1_mask;
> +    uint64_t omr2_base;
> +    uint64_t omr2_mask;
> +    uint64_t omr3_base;
> +    uint64_t omr3_mask;
> +    uint64_t reg_base;
> +    uint32_t reg_mask;
> +    uint32_t special;
> +    uint32_t cfg;
> +} PPC460EXPCIEState;
> +
> +#define DCRN_PCIE0_BASE 0x100
> +#define DCRN_PCIE1_BASE 0x120
> +
> +enum {
> +    PEGPL_CFGBAH = 0x0,
> +    PEGPL_CFGBAL,
> +    PEGPL_CFGMSK,
> +    PEGPL_MSGBAH,
> +    PEGPL_MSGBAL,
> +    PEGPL_MSGMSK,
> +    PEGPL_OMR1BAH,
> +    PEGPL_OMR1BAL,
> +    PEGPL_OMR1MSKH,
> +    PEGPL_OMR1MSKL,
> +    PEGPL_OMR2BAH,
> +    PEGPL_OMR2BAL,
> +    PEGPL_OMR2MSKH,
> +    PEGPL_OMR2MSKL,
> +    PEGPL_OMR3BAH,
> +    PEGPL_OMR3BAL,
> +    PEGPL_OMR3MSKH,
> +    PEGPL_OMR3MSKL,
> +    PEGPL_REGBAH,
> +    PEGPL_REGBAL,
> +    PEGPL_REGMSK,
> +    PEGPL_SPECIAL,
> +    PEGPL_CFG,
> +};
> +
> +static uint32_t dcr_read_pcie(void *opaque, int dcrn)
> +{
> +    PPC460EXPCIEState *state = opaque;
> +    uint32_t ret = 0;
> +
> +    switch (dcrn - state->dcrn_base) {
> +    case PEGPL_CFGBAH:
> +        ret = state->cfg_base >> 32;
> +        break;
> +    case PEGPL_CFGBAL:
> +        ret = state->cfg_base;
> +        break;
> +    case PEGPL_CFGMSK:
> +        ret = state->cfg_mask;
> +        break;
> +    case PEGPL_MSGBAH:
> +        ret = state->msg_base >> 32;
> +        break;
> +    case PEGPL_MSGBAL:
> +        ret = state->msg_base;
> +        break;
> +    case PEGPL_MSGMSK:
> +        ret = state->msg_mask;
> +        break;
> +    case PEGPL_OMR1BAH:
> +        ret = state->omr1_base >> 32;
> +        break;
> +    case PEGPL_OMR1BAL:
> +        ret = state->omr1_base;
> +        break;
> +    case PEGPL_OMR1MSKH:
> +        ret = state->omr1_mask >> 32;
> +        break;
> +    case PEGPL_OMR1MSKL:
> +        ret = state->omr1_mask;
> +        break;
> +    case PEGPL_OMR2BAH:
> +        ret = state->omr2_base >> 32;
> +        break;
> +    case PEGPL_OMR2BAL:
> +        ret = state->omr2_base;
> +        break;
> +    case PEGPL_OMR2MSKH:
> +        ret = state->omr2_mask >> 32;
> +        break;
> +    case PEGPL_OMR2MSKL:
> +        ret = state->omr3_mask;
> +        break;
> +    case PEGPL_OMR3BAH:
> +        ret = state->omr3_base >> 32;
> +        break;
> +    case PEGPL_OMR3BAL:
> +        ret = state->omr3_base;
> +        break;
> +    case PEGPL_OMR3MSKH:
> +        ret = state->omr3_mask >> 32;
> +        break;
> +    case PEGPL_OMR3MSKL:
> +        ret = state->omr3_mask;
> +        break;
> +    case PEGPL_REGBAH:
> +        ret = state->reg_base >> 32;
> +        break;
> +    case PEGPL_REGBAL:
> +        ret = state->reg_base;
> +        break;
> +    case PEGPL_REGMSK:
> +        ret = state->reg_mask;
> +        break;
> +    case PEGPL_SPECIAL:
> +        ret = state->special;
> +        break;
> +    case PEGPL_CFG:
> +        ret = state->cfg;
> +        break;
> +    }
> +
> +    return ret;
> +}
> +
> +static void dcr_write_pcie(void *opaque, int dcrn, uint32_t val)
> +{
> +    PPC460EXPCIEState *s = opaque;
> +    uint64_t size;
> +
> +    switch (dcrn - s->dcrn_base) {
> +    case PEGPL_CFGBAH:
> +        s->cfg_base = ((uint64_t)val << 32) | (s->cfg_base & 0xffffffff);
> +        break;
> +    case PEGPL_CFGBAL:
> +        s->cfg_base = (s->cfg_base & 0xffffffff00000000ULL) | val;
> +        break;
> +    case PEGPL_CFGMSK:
> +        s->cfg_mask = val;
> +        size = ~(val & 0xfffffffe) + 1;
> +        qemu_mutex_lock_iothread();
> +        pcie_host_mmcfg_update(PCIE_HOST_BRIDGE(s), val & 1, s->cfg_base, size);
> +        qemu_mutex_unlock_iothread();
> +        break;
> +    case PEGPL_MSGBAH:
> +        s->msg_base = ((uint64_t)val << 32) | (s->msg_base & 0xffffffff);
> +        break;
> +    case PEGPL_MSGBAL:
> +        s->msg_base = (s->msg_base & 0xffffffff00000000ULL) | val;
> +        break;
> +    case PEGPL_MSGMSK:
> +        s->msg_mask = val;
> +        break;
> +    case PEGPL_OMR1BAH:
> +        s->omr1_base = ((uint64_t)val << 32) | (s->omr1_base & 0xffffffff);
> +        break;
> +    case PEGPL_OMR1BAL:
> +        s->omr1_base = (s->omr1_base & 0xffffffff00000000ULL) | val;
> +        break;
> +    case PEGPL_OMR1MSKH:
> +        s->omr1_mask = ((uint64_t)val << 32) | (s->omr1_mask & 0xffffffff);
> +        break;
> +    case PEGPL_OMR1MSKL:
> +        s->omr1_mask = (s->omr1_mask & 0xffffffff00000000ULL) | val;
> +        break;
> +    case PEGPL_OMR2BAH:
> +        s->omr2_base = ((uint64_t)val << 32) | (s->omr2_base & 0xffffffff);
> +        break;
> +    case PEGPL_OMR2BAL:
> +        s->omr2_base = (s->omr2_base & 0xffffffff00000000ULL) | val;
> +        break;
> +    case PEGPL_OMR2MSKH:
> +        s->omr2_mask = ((uint64_t)val << 32) | (s->omr2_mask & 0xffffffff);
> +        break;
> +    case PEGPL_OMR2MSKL:
> +        s->omr2_mask = (s->omr2_mask & 0xffffffff00000000ULL) | val;
> +        break;
> +    case PEGPL_OMR3BAH:
> +        s->omr3_base = ((uint64_t)val << 32) | (s->omr3_base & 0xffffffff);
> +        break;
> +    case PEGPL_OMR3BAL:
> +        s->omr3_base = (s->omr3_base & 0xffffffff00000000ULL) | val;
> +        break;
> +    case PEGPL_OMR3MSKH:
> +        s->omr3_mask = ((uint64_t)val << 32) | (s->omr3_mask & 0xffffffff);
> +        break;
> +    case PEGPL_OMR3MSKL:
> +        s->omr3_mask = (s->omr3_mask & 0xffffffff00000000ULL) | val;
> +        break;
> +    case PEGPL_REGBAH:
> +        s->reg_base = ((uint64_t)val << 32) | (s->reg_base & 0xffffffff);
> +        break;
> +    case PEGPL_REGBAL:
> +        s->reg_base = (s->reg_base & 0xffffffff00000000ULL) | val;
> +        break;
> +    case PEGPL_REGMSK:
> +        s->reg_mask = val;
> +        /* FIXME: how is size encoded? */
> +        size = (val == 0x7001 ? 4096 : ~(val & 0xfffffffe) + 1);
> +        break;
> +    case PEGPL_SPECIAL:
> +        s->special = val;
> +        break;
> +    case PEGPL_CFG:
> +        s->cfg = val;
> +        break;
> +    }
> +}
> +
> +static void ppc460ex_set_irq(void *opaque, int irq_num, int level)
> +{
> +       PPC460EXPCIEState *s = opaque;
> +       qemu_set_irq(s->irq[irq_num], level);
> +}
> +
> +static void ppc460ex_pcie_realize(DeviceState *dev, Error **errp)
> +{
> +    PPC460EXPCIEState *s = PPC460EX_PCIE_HOST(dev);
> +    PCIHostState *pci = PCI_HOST_BRIDGE(dev);
> +    int i, id;
> +    char buf[16];
> +
> +    switch (s->dcrn_base) {
> +    case DCRN_PCIE0_BASE:
> +        id = 0;
> +        break;
> +    case DCRN_PCIE1_BASE:
> +        id = 1;
> +        break;
> +    }
> +    snprintf(buf, sizeof(buf), "pcie%d-io", id);
> +    memory_region_init(&s->iomem, OBJECT(s), buf, UINT64_MAX);
> +    for (i = 0; i < 4; i++) {
> +        sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[i]);
> +    }
> +    snprintf(buf, sizeof(buf), "pcie.%d", id);
> +    pci->bus = pci_register_root_bus(DEVICE(s), buf, ppc460ex_set_irq,
> +                                pci_swizzle_map_irq_fn, s, &s->iomem,
> +                                get_system_io(), 0, 4, TYPE_PCIE_BUS);
> +}
> +
> +static Property ppc460ex_pcie_props[] = {
> +    DEFINE_PROP_INT32("dcrn-base", PPC460EXPCIEState, dcrn_base, -1),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void ppc460ex_pcie_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
> +    dc->realize = ppc460ex_pcie_realize;
> +    dc->props = ppc460ex_pcie_props;
> +    dc->hotpluggable = false;
> +}
> +
> +static const TypeInfo ppc460ex_pcie_host_info = {
> +    .name = TYPE_PPC460EX_PCIE_HOST,
> +    .parent = TYPE_PCIE_HOST_BRIDGE,
> +    .instance_size = sizeof(PPC460EXPCIEState),
> +    .class_init = ppc460ex_pcie_class_init,
> +};
> +
> +static void ppc460ex_pcie_register(void)
> +{
> +    type_register_static(&ppc460ex_pcie_host_info);
> +}
> +
> +type_init(ppc460ex_pcie_register)
> +
> +static void ppc460ex_pcie_register_dcrs(PPC460EXPCIEState *s, CPUPPCState *env)
> +{
> +    ppc_dcr_register(env, s->dcrn_base + PEGPL_CFGBAH, s,
> +                     &dcr_read_pcie, &dcr_write_pcie);
> +    ppc_dcr_register(env, s->dcrn_base + PEGPL_CFGBAL, s,
> +                     &dcr_read_pcie, &dcr_write_pcie);
> +    ppc_dcr_register(env, s->dcrn_base + PEGPL_CFGMSK, s,
> +                     &dcr_read_pcie, &dcr_write_pcie);
> +    ppc_dcr_register(env, s->dcrn_base + PEGPL_MSGBAH, s,
> +                     &dcr_read_pcie, &dcr_write_pcie);
> +    ppc_dcr_register(env, s->dcrn_base + PEGPL_MSGBAL, s,
> +                     &dcr_read_pcie, &dcr_write_pcie);
> +    ppc_dcr_register(env, s->dcrn_base + PEGPL_MSGMSK, s,
> +                     &dcr_read_pcie, &dcr_write_pcie);
> +    ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR1BAH, s,
> +                     &dcr_read_pcie, &dcr_write_pcie);
> +    ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR1BAL, s,
> +                     &dcr_read_pcie, &dcr_write_pcie);
> +    ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR1MSKH, s,
> +                     &dcr_read_pcie, &dcr_write_pcie);
> +    ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR1MSKL, s,
> +                     &dcr_read_pcie, &dcr_write_pcie);
> +    ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR2BAH, s,
> +                     &dcr_read_pcie, &dcr_write_pcie);
> +    ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR2BAL, s,
> +                     &dcr_read_pcie, &dcr_write_pcie);
> +    ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR2MSKH, s,
> +                     &dcr_read_pcie, &dcr_write_pcie);
> +    ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR2MSKL, s,
> +                     &dcr_read_pcie, &dcr_write_pcie);
> +    ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR3BAH, s,
> +                     &dcr_read_pcie, &dcr_write_pcie);
> +    ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR3BAL, s,
> +                     &dcr_read_pcie, &dcr_write_pcie);
> +    ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR3MSKH, s,
> +                     &dcr_read_pcie, &dcr_write_pcie);
> +    ppc_dcr_register(env, s->dcrn_base + PEGPL_OMR3MSKL, s,
> +                     &dcr_read_pcie, &dcr_write_pcie);
> +    ppc_dcr_register(env, s->dcrn_base + PEGPL_REGBAH, s,
> +                     &dcr_read_pcie, &dcr_write_pcie);
> +    ppc_dcr_register(env, s->dcrn_base + PEGPL_REGBAL, s,
> +                     &dcr_read_pcie, &dcr_write_pcie);
> +    ppc_dcr_register(env, s->dcrn_base + PEGPL_REGMSK, s,
> +                     &dcr_read_pcie, &dcr_write_pcie);
> +    ppc_dcr_register(env, s->dcrn_base + PEGPL_SPECIAL, s,
> +                     &dcr_read_pcie, &dcr_write_pcie);
> +    ppc_dcr_register(env, s->dcrn_base + PEGPL_CFG, s,
> +                     &dcr_read_pcie, &dcr_write_pcie);
> +}
> +
> +void ppc460ex_pcie_init(CPUPPCState *env)
> +{
> +    DeviceState *dev;
> +
> +    dev = qdev_create(NULL, TYPE_PPC460EX_PCIE_HOST);
> +    qdev_prop_set_int32(dev, "dcrn-base", DCRN_PCIE0_BASE);
> +    qdev_init_nofail(dev);
> +    object_property_set_bool(OBJECT(dev), true, "realized", NULL);
> +    ppc460ex_pcie_register_dcrs(PPC460EX_PCIE_HOST(dev), env);
> +
> +    dev = qdev_create(NULL, TYPE_PPC460EX_PCIE_HOST);
> +    qdev_prop_set_int32(dev, "dcrn-base", DCRN_PCIE1_BASE);
> +    qdev_init_nofail(dev);
> +    object_property_set_bool(OBJECT(dev), true, "realized", NULL);
> +    ppc460ex_pcie_register_dcrs(PPC460EX_PCIE_HOST(dev), env);
> +}
> diff --git a/include/hw/pci/pcie_host.h b/include/hw/pci/pcie_host.h
> index 4d23c80..3f7b988 100644
> --- a/include/hw/pci/pcie_host.h
> +++ b/include/hw/pci/pcie_host.h
> @@ -65,7 +65,7 @@ void pcie_host_mmcfg_update(PCIExpressHost *e,
>   * bit 12 - 14: function number
>   * bit  0 - 11: offset in configuration space of a given device
>   */
> -#define PCIE_MMCFG_SIZE_MAX             (1ULL << 28)
> +#define PCIE_MMCFG_SIZE_MAX             (1ULL << 29)
>  #define PCIE_MMCFG_SIZE_MIN             (1ULL << 20)
>  #define PCIE_MMCFG_BUS_BIT              20
>  #define PCIE_MMCFG_BUS_MASK             0x1ff

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [PATCH v2 3/3] ppc: Add aCube Sam460ex board
  2018-02-15 21:27 ` [Qemu-devel] [PATCH v2 3/3] ppc: Add aCube Sam460ex board BALATON Zoltan
@ 2018-02-16  3:10   ` David Gibson
  2018-02-16 10:45     ` [Qemu-devel] [Qemu-ppc] " BALATON Zoltan
  0 siblings, 1 reply; 16+ messages in thread
From: David Gibson @ 2018-02-16  3:10 UTC (permalink / raw)
  To: BALATON Zoltan; +Cc: qemu-devel, qemu-ppc, Alexander Graf, Francois Revol

[-- Attachment #1: Type: text/plain, Size: 24394 bytes --]

On Thu, Feb 15, 2018 at 10:27:06PM +0100, BALATON Zoltan wrote:
> Add emulation of aCube Sam460ex board based on AMCC 460EX embedded SoC.
> This is not a complete implementation yet with a lot of components
> still missing but enough for the U-Boot firmware to start and to boot
> a Linux kernel or AROS.
> 
> Signed-off-by: François Revol <revol@free.fr>
> Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
> ---
> 
> v2:
> - Rebased to latest changes on master
> - Replaced printfs with error_report

This has a conflict in hw/ppc/Makefile.objs.  Looks like it was based
on some other patch that added ppc440_pcix.o.  That's not there
upstream.

> 
>  default-configs/ppc-softmmu.mak    |   2 +
>  default-configs/ppcemb-softmmu.mak |   1 +
>  hw/ppc/Makefile.objs               |   3 +-
>  hw/ppc/sam460ex.c                  | 603 +++++++++++++++++++++++++++++++++++++
>  4 files changed, 608 insertions(+), 1 deletion(-)
>  create mode 100644 hw/ppc/sam460ex.c
> 
> diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak
> index 76e29cf..4d7be45 100644
> --- a/default-configs/ppc-softmmu.mak
> +++ b/default-configs/ppc-softmmu.mak
> @@ -21,6 +21,8 @@ CONFIG_E500=y
>  CONFIG_OPENPIC_KVM=$(call land,$(CONFIG_E500),$(CONFIG_KVM))
>  CONFIG_PLATFORM_BUS=y
>  CONFIG_ETSEC=y
> +# For Sam460ex
> +CONFIG_USB_EHCI_SYSBUS=y
>  CONFIG_SM501=y
>  CONFIG_IDE_SII3112=y
>  CONFIG_I2C=y
> diff --git a/default-configs/ppcemb-softmmu.mak b/default-configs/ppcemb-softmmu.mak
> index bc5e1b3..67d18b2 100644
> --- a/default-configs/ppcemb-softmmu.mak
> +++ b/default-configs/ppcemb-softmmu.mak
> @@ -15,6 +15,7 @@ CONFIG_PTIMER=y
>  CONFIG_I8259=y
>  CONFIG_XILINX=y
>  CONFIG_XILINX_ETHLITE=y
> +CONFIG_USB_EHCI_SYSBUS=y
>  CONFIG_SM501=y
>  CONFIG_IDE_SII3112=y
>  CONFIG_I2C=y
> diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs
> index bddc742..86d82a6 100644
> --- a/hw/ppc/Makefile.objs
> +++ b/hw/ppc/Makefile.objs
> @@ -13,7 +13,8 @@ endif
>  obj-$(CONFIG_PSERIES) += spapr_rtas_ddw.o
>  # PowerPC 4xx boards
>  obj-y += ppc4xx_devs.o ppc405_uc.o
> -obj-$(CONFIG_PPC4XX) += ppc4xx_pci.o ppc405_boards.o ppc440_bamboo.o ppc440_pcix.o
> +obj-$(CONFIG_PPC4XX) += ppc4xx_pci.o ppc405_boards.o
> +obj-$(CONFIG_PPC4XX) += ppc440_bamboo.o ppc440_pcix.o ppc440_uc.o sam460ex.o
>  # PReP
>  obj-$(CONFIG_PREP) += prep.o
>  obj-$(CONFIG_PREP) += prep_systemio.o
> diff --git a/hw/ppc/sam460ex.c b/hw/ppc/sam460ex.c
> new file mode 100644
> index 0000000..ff99cf9
> --- /dev/null
> +++ b/hw/ppc/sam460ex.c
> @@ -0,0 +1,603 @@
> +/*
> + * QEMU aCube Sam460ex board emulation
> + *
> + * Copyright (c) 2012 François Revol
> + * Copyright (c) 2016-2018 BALATON Zoltan
> + *
> + * This file is derived from hw/ppc440_bamboo.c,
> + * the copyright for that material belongs to the original owners.
> + *
> + * This work is licensed under the GNU GPL license version 2 or later.
> + *
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qemu-common.h"
> +#include "qemu/cutils.h"
> +#include "qemu/error-report.h"
> +#include "qapi/error.h"
> +#include "hw/hw.h"
> +#include "sysemu/blockdev.h"
> +#include "hw/boards.h"
> +#include "sysemu/kvm.h"
> +#include "kvm_ppc.h"
> +#include "sysemu/device_tree.h"
> +#include "sysemu/block-backend.h"
> +#include "hw/loader.h"
> +#include "elf.h"
> +#include "exec/address-spaces.h"
> +#include "exec/memory.h"
> +#include "hw/ppc/ppc440.h"
> +#include "hw/ppc/ppc405.h"
> +#include "hw/block/flash.h"
> +#include "sysemu/sysemu.h"
> +#include "sysemu/qtest.h"
> +#include "hw/sysbus.h"
> +#include "hw/char/serial.h"
> +#include "hw/i2c/ppc4xx_i2c.h"
> +#include "hw/i2c/smbus.h"
> +#include "hw/usb/hcd-ehci.h"
> +
> +#define BINARY_DEVICE_TREE_FILE "sam460ex.dtb"
> +#define UBOOT_FILENAME "u-boot-sam460-20100605.bin"
> +/* to extract the official U-Boot bin from the updater: */
> +/* dd bs=1 skip=$(($(stat -c '%s' updater/updater-460) - 0x80000)) \
> +     if=updater/updater-460 of=u-boot-sam460-20100605.bin */
> +
> +/* from Sam460 U-Boot include/configs/Sam460ex.h */
> +#define FLASH_BASE             0xfff00000
> +#define FLASH_BASE_H           0x4
> +#define FLASH_SIZE             (1 << 20)
> +#define UBOOT_LOAD_BASE        0xfff80000
> +#define UBOOT_SIZE             0x00080000
> +#define UBOOT_ENTRY            0xfffffffc
> +
> +/* from U-Boot */
> +#define EPAPR_MAGIC           (0x45504150)
> +#define KERNEL_ADDR           0x1000000
> +#define FDT_ADDR              0x1800000
> +#define RAMDISK_ADDR          0x1900000
> +
> +/* Sam460ex IRQ MAP:
> +   IRQ0  = ETH_INT
> +   IRQ1  = FPGA_INT
> +   IRQ2  = PCI_INT (PCIA, PCIB, PCIC, PCIB)
> +   IRQ3  = FPGA_INT2
> +   IRQ11 = RTC_INT
> +   IRQ12 = SM502_INT
> +*/
> +
> +#define SDRAM_NR_BANKS 4
> +
> +/* FIXME: See u-boot.git 8ac41e, also fix in ppc440_uc.c */
> +static const unsigned int ppc460ex_sdram_bank_sizes[] = {
> +    1024 << 20, 512 << 20, 256 << 20, 128 << 20, 64 << 20, 32 << 20, 0
> +};
> +
> +struct boot_info {
> +    uint32_t dt_base;
> +    uint32_t dt_size;
> +    uint32_t entry;
> +};
> +
> +/*****************************************************************************/
> +/* SPD eeprom content from mips_malta.c */
> +
> +struct _eeprom24c0x_t {
> +  uint8_t tick;
> +  uint8_t address;
> +  uint8_t command;
> +  uint8_t ack;
> +  uint8_t scl;
> +  uint8_t sda;
> +  uint8_t data;
> +  uint8_t contents[256];
> +};
> +
> +typedef struct _eeprom24c0x_t eeprom24c0x_t;
> +
> +static eeprom24c0x_t spd_eeprom = {
> +    .contents = {
> +        /* 00000000: */ 0x80, 0x08, 0xFF, 0x0D, 0x0A, 0xFF, 0x40, 0x00,
> +        /* 00000008: */ 0x04, 0x75, 0x54, 0x00, 0x82, 0x08, 0x00, 0x01,
> +        /* 00000010: */ 0x8F, 0x04, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00,
> +        /* 00000018: */ 0x00, 0x00, 0x00, 0x14, 0x0F, 0x14, 0x2D, 0xFF,
> +        /* 00000020: */ 0x15, 0x08, 0x15, 0x08, 0x00, 0x00, 0x00, 0x00,
> +        /* 00000028: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +        /* 00000030: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +        /* 00000038: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0xD0,
> +        /* 00000040: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +        /* 00000048: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +        /* 00000050: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +        /* 00000058: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +        /* 00000060: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +        /* 00000068: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +        /* 00000070: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +        /* 00000078: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xF4,
> +    },
> +};
> +
> +static void generate_eeprom_spd(uint8_t *eeprom, ram_addr_t ram_size)
> +{
> +    enum { SDR = 0x4, DDR1 = 0x7, DDR2 = 0x8 } type;
> +    uint8_t *spd = spd_eeprom.contents;
> +    uint8_t nbanks = 0;
> +    uint16_t density = 0;
> +    int i;
> +
> +    /* work in terms of MB */
> +    ram_size >>= 20;
> +
> +    while ((ram_size >= 4) && (nbanks <= 2)) {
> +        int sz_log2 = MIN(31 - clz32(ram_size), 14);
> +        nbanks++;
> +        density |= 1 << (sz_log2 - 2);
> +        ram_size -= 1 << sz_log2;
> +    }
> +
> +    /* split to 2 banks if possible */
> +    if ((nbanks == 1) && (density > 1)) {
> +        nbanks++;
> +        density >>= 1;
> +    }
> +
> +    if (density & 0xff00) {
> +        density = (density & 0xe0) | ((density >> 8) & 0x1f);
> +        type = DDR2;
> +    } else if (!(density & 0x1f)) {
> +        type = DDR2;
> +    } else {
> +        type = SDR;
> +    }
> +
> +    if (ram_size) {
> +        warn_report("SPD cannot represent final " RAM_ADDR_FMT "MB"
> +                    " of SDRAM", ram_size);
> +    }
> +
> +    /* fill in SPD memory information */
> +    spd[2] = type;
> +    spd[5] = nbanks;
> +    spd[31] = density;
> +
> +    /* XXX: this is totally random */
> +    spd[9] = 0x10; /* CAS tcyc */
> +    spd[18] = 0x20; /* CAS bit */
> +    spd[23] = 0x10; /* CAS tcyc */
> +    spd[25] = 0x10; /* CAS tcyc */
> +
> +    /* checksum */
> +    spd[63] = 0;
> +    for (i = 0; i < 63; i++) {
> +        spd[63] += spd[i];
> +    }
> +
> +    /* copy for SMBUS */
> +    memcpy(eeprom, spd, sizeof(spd_eeprom.contents));
> +}
> +
> +static void generate_eeprom_serial(uint8_t *eeprom)
> +{
> +    int i, pos = 0;
> +    uint8_t mac[6] = { 0x00 };
> +    uint8_t sn[5] = { 0x01, 0x23, 0x45, 0x67, 0x89 };
> +
> +    /* version */
> +    eeprom[pos++] = 0x01;
> +
> +    /* count */
> +    eeprom[pos++] = 0x02;
> +
> +    /* MAC address */
> +    eeprom[pos++] = 0x01; /* MAC */
> +    eeprom[pos++] = 0x06; /* length */
> +    memcpy(&eeprom[pos], mac, sizeof(mac));
> +    pos += sizeof(mac);
> +
> +    /* serial number */
> +    eeprom[pos++] = 0x02; /* serial */
> +    eeprom[pos++] = 0x05; /* length */
> +    memcpy(&eeprom[pos], sn, sizeof(sn));
> +    pos += sizeof(sn);
> +
> +    /* checksum */
> +    eeprom[pos] = 0;
> +    for (i = 0; i < pos; i++) {
> +        eeprom[pos] += eeprom[i];
> +    }
> +}
> +
> +/*****************************************************************************/
> +
> +static int sam460ex_load_uboot(void)
> +{
> +    DriveInfo *dinfo;
> +    BlockBackend *blk = NULL;
> +    hwaddr base = FLASH_BASE | ((hwaddr)FLASH_BASE_H << 32);
> +    long bios_size = FLASH_SIZE;
> +    int fl_sectors;
> +
> +    dinfo = drive_get(IF_PFLASH, 0, 0);
> +    if (dinfo) {
> +        blk = blk_by_legacy_dinfo(dinfo);
> +        bios_size = blk_getlength(blk);
> +    }
> +    fl_sectors = (bios_size + 65535) >> 16;
> +
> +    if (!pflash_cfi01_register(base, NULL, "sam460ex.flash", bios_size,
> +                               blk, (64 * 1024), fl_sectors,
> +                               1, 0x89, 0x18, 0x0000, 0x0, 1)) {
> +        error_report("qemu: Error registering flash memory.");
> +        /* XXX: return an error instead? */
> +        exit(1);
> +    }
> +
> +    if (!blk) {
> +        /*error_report("No flash image given with the 'pflash' parameter,"
> +                " using default u-boot image");*/
> +        base = UBOOT_LOAD_BASE | ((hwaddr)FLASH_BASE_H << 32);
> +        rom_add_file_fixed(UBOOT_FILENAME, base, -1);
> +    }
> +
> +    return 0;
> +}
> +
> +static int sam460ex_load_device_tree(hwaddr addr,
> +                                     uint32_t ramsize,
> +                                     hwaddr initrd_base,
> +                                     hwaddr initrd_size,
> +                                     const char *kernel_cmdline)
> +{
> +    int ret = -1;
> +    uint32_t mem_reg_property[] = { 0, 0, cpu_to_be32(ramsize) };
> +    char *filename;
> +    int fdt_size;
> +    void *fdt;
> +    uint32_t tb_freq = 400000000;
> +    uint32_t clock_freq = 400000000;
> +
> +    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
> +    if (!filename) {
> +        goto out;
> +    }
> +    fdt = load_device_tree(filename, &fdt_size);
> +    g_free(filename);
> +    if (fdt == NULL) {
> +        goto out;
> +    }
> +
> +    /* Manipulate device tree in memory. */
> +
> +    ret = qemu_fdt_setprop(fdt, "/memory", "reg", mem_reg_property,
> +                               sizeof(mem_reg_property));
> +    if (ret < 0) {
> +        error_report("couldn't set /memory/reg");
> +    }
> +
> +    /* default FDT doesn't have a /chosen node... */
> +    qemu_fdt_add_subnode(fdt, "/chosen");
> +
> +    ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start",
> +                                    initrd_base);
> +    if (ret < 0) {
> +        error_report("couldn't set /chosen/linux,initrd-start");
> +    }
> +
> +    ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
> +                                    (initrd_base + initrd_size));
> +    if (ret < 0) {
> +        error_report("couldn't set /chosen/linux,initrd-end");
> +    }
> +
> +    ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
> +                                      kernel_cmdline);
> +    if (ret < 0) {
> +        error_report("couldn't set /chosen/bootargs");
> +    }
> +
> +    /* Copy data from the host device tree into the guest. Since the guest can
> +     * directly access the timebase without host involvement, we must expose
> +     * the correct frequencies. */
> +    if (kvm_enabled()) {
> +        tb_freq = kvmppc_get_tbfreq();
> +        clock_freq = kvmppc_get_clockfreq();
> +    }
> +
> +    qemu_fdt_setprop_cell(fdt, "/cpus/cpu@0", "clock-frequency",
> +                              clock_freq);
> +    qemu_fdt_setprop_cell(fdt, "/cpus/cpu@0", "timebase-frequency",
> +                              tb_freq);
> +
> +    rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
> +    g_free(fdt);
> +    ret = fdt_size;
> +
> +out:
> +
> +    return ret;
> +}
> +
> +/* Create reset TLB entries for BookE, mapping only the flash memory.  */
> +static void mmubooke_create_initial_mapping_uboot(CPUPPCState *env)
> +{
> +    ppcemb_tlb_t *tlb = &env->tlb.tlbe[0];
> +
> +    /* on reset the flash is mapped by a shadow TLB,
> +     * but since we don't implement them we need to use
> +     * the same values U-Boot will use to avoid a fault.
> +     */
> +    tlb->attr = 0;
> +    tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
> +    tlb->size = 0x10000000; /* up to 0xffffffff  */
> +    tlb->EPN = 0xf0000000 & TARGET_PAGE_MASK;
> +    tlb->RPN = (0xf0000000 & TARGET_PAGE_MASK) | 0x4;
> +    tlb->PID = 0;
> +}
> +
> +/* Create reset TLB entries for BookE, spanning the 32bit addr space.  */
> +static void mmubooke_create_initial_mapping(CPUPPCState *env,
> +                                     target_ulong va,
> +                                     hwaddr pa)
> +{
> +    ppcemb_tlb_t *tlb = &env->tlb.tlbe[0];
> +
> +    tlb->attr = 0;
> +    tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
> +    tlb->size = 1 << 31; /* up to 0x80000000  */
> +    tlb->EPN = va & TARGET_PAGE_MASK;
> +    tlb->RPN = pa & TARGET_PAGE_MASK;
> +    tlb->PID = 0;
> +}
> +
> +static void main_cpu_reset(void *opaque)
> +{
> +    PowerPCCPU *cpu = opaque;
> +    CPUPPCState *env = &cpu->env;
> +    struct boot_info *bi = env->load_info;
> +
> +    cpu_reset(CPU(cpu));
> +
> +    /* either we have a kernel to boot or we jump to U-Boot */
> +    if (bi->entry != UBOOT_ENTRY) {
> +        env->gpr[1] = (16 << 20) - 8;
> +        env->gpr[3] = FDT_ADDR;
> +        env->nip = bi->entry;
> +
> +        /* Create a mapping for the kernel.  */
> +        mmubooke_create_initial_mapping(env, 0, 0);
> +        env->gpr[6] = tswap32(EPAPR_MAGIC);
> +        env->gpr[7] = (16 << 20) - 8; /*bi->ima_size;*/
> +
> +    } else {
> +        env->nip = UBOOT_ENTRY;
> +        mmubooke_create_initial_mapping_uboot(env);
> +    }
> +}
> +
> +static void sam460ex_init(MachineState *machine)
> +{
> +    MemoryRegion *address_space_mem = get_system_memory();
> +    MemoryRegion *isa = g_new(MemoryRegion, 1);
> +    MemoryRegion *ram_memories = g_new(MemoryRegion, SDRAM_NR_BANKS);
> +    hwaddr ram_bases[SDRAM_NR_BANKS];
> +    hwaddr ram_sizes[SDRAM_NR_BANKS];
> +    MemoryRegion *l2cache_ram = g_new(MemoryRegion, 1);
> +    qemu_irq *irqs, *uic[4];
> +    PCIBus *pci_bus;
> +    PowerPCCPU *cpu;
> +    CPUPPCState *env;
> +    PPC4xxI2CState *i2c[2];
> +    hwaddr entry = UBOOT_ENTRY;
> +    hwaddr loadaddr = 0;
> +    target_long initrd_size = 0;
> +    DeviceState *dev;
> +    SysBusDevice *sbdev;
> +    int success;
> +    int i;
> +    struct boot_info *boot_info;
> +    const size_t smbus_eeprom_size = 8 * 256;
> +    uint8_t *smbus_eeprom_buf = g_malloc0(smbus_eeprom_size);
> +
> +    cpu = POWERPC_CPU(cpu_create(machine->cpu_type));
> +    env = &cpu->env;
> +    if (env->mmu_model != POWERPC_MMU_BOOKE) {
> +        error_report("Only MMU model BookE is supported by this machine.");
> +        exit(1);
> +    }
> +
> +#ifdef TARGET_PPCEMB
> +    if (!qtest_enabled()) {
> +        warn_report("qemu-system-ppcemb is deprecated, "
> +                    "please use qemu-system-ppc instead.");
> +    }
> +#endif
> +
> +    qemu_register_reset(main_cpu_reset, cpu);
> +    boot_info = g_malloc0(sizeof(*boot_info));
> +    env->load_info = boot_info;
> +
> +    ppc_booke_timers_init(cpu, 50000000, 0);
> +    ppc_dcr_init(env, NULL, NULL);
> +
> +    /* PLB arbitrer */
> +    ppc4xx_plb_init(env);
> +
> +    /* interrupt controllers */
> +    irqs = g_malloc0(sizeof(*irqs) * PPCUIC_OUTPUT_NB);
> +    irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
> +    irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
> +    uic[0] = ppcuic_init(env, irqs, 0xc0, 0, 1);
> +    uic[1] = ppcuic_init(env, &uic[0][30], 0xd0, 0, 1);
> +    uic[2] = ppcuic_init(env, &uic[0][10], 0xe0, 0, 1);
> +    uic[3] = ppcuic_init(env, &uic[0][16], 0xf0, 0, 1);
> +
> +    /* SDRAM controller */
> +    memset(ram_bases, 0, sizeof(ram_bases));
> +    memset(ram_sizes, 0, sizeof(ram_sizes));
> +    /* put all RAM on first bank because board has one slot
> +     * and firmware only checks that */
> +    machine->ram_size = ppc4xx_sdram_adjust(machine->ram_size, 1,
> +                                   ram_memories, ram_bases, ram_sizes,
> +                                   ppc460ex_sdram_bank_sizes);
> +
> +    /* FIXME: does 460EX have ECC interrupts? */
> +    ppc440_sdram_init(env, SDRAM_NR_BANKS, ram_memories,
> +                      ram_bases, ram_sizes, 1);
> +
> +    /* generate SPD EEPROM data */
> +    for (i = 0; i < SDRAM_NR_BANKS; i++) {
> +        generate_eeprom_spd(&smbus_eeprom_buf[i * 256], ram_sizes[i]);
> +    }
> +    generate_eeprom_serial(&smbus_eeprom_buf[4 * 256]);
> +    generate_eeprom_serial(&smbus_eeprom_buf[6 * 256]);
> +
> +    /* IIC controllers */
> +    dev = sysbus_create_simple(TYPE_PPC4xx_I2C, 0x4ef600700, uic[0][2]);
> +    i2c[0] = PPC4xx_I2C(dev);
> +    object_property_set_bool(OBJECT(dev), true, "realized", NULL);
> +    smbus_eeprom_init(i2c[0]->bus, 8, smbus_eeprom_buf, smbus_eeprom_size);
> +    g_free(smbus_eeprom_buf);
> +
> +    dev = sysbus_create_simple(TYPE_PPC4xx_I2C, 0x4ef600800, uic[0][3]);
> +    i2c[1] = PPC4xx_I2C(dev);
> +
> +    /* External bus controller */
> +    ppc405_ebc_init(env);
> +
> +    /* CPR */
> +    ppc4xx_cpr_init(env);
> +
> +    /* PLB to AHB bridge */
> +    ppc4xx_ahb_init(env);
> +
> +    /* System DCRs */
> +    ppc4xx_sdr_init(env);
> +
> +    /* MAL */
> +    ppc4xx_mal_init(env, 4, 16, &uic[2][3]);
> +
> +    /* 256K of L2 cache as memory */
> +    ppc4xx_l2sram_init(env);
> +    /* FIXME: remove this after fixing l2sram mapping in ppc440_uc.c? */
> +    memory_region_init_ram(l2cache_ram, NULL, "ppc440.l2cache_ram", 256 << 10,
> +                           &error_abort);
> +    memory_region_add_subregion(address_space_mem, 0x400000000LL, l2cache_ram);
> +
> +    /* USB */
> +    sysbus_create_simple(TYPE_PPC4xx_EHCI, 0x4bffd0400, uic[2][29]);
> +    dev = qdev_create(NULL, "sysbus-ohci");
> +    qdev_prop_set_string(dev, "masterbus", "usb-bus.0");
> +    qdev_prop_set_uint32(dev, "num-ports", 6);
> +    qdev_init_nofail(dev);
> +    sbdev = SYS_BUS_DEVICE(dev);
> +    sysbus_mmio_map(sbdev, 0, 0x4bffd0000);
> +    sysbus_connect_irq(sbdev, 0, uic[2][30]);
> +    usb_create_simple(usb_bus_find(-1), "usb-kbd");
> +    usb_create_simple(usb_bus_find(-1), "usb-mouse");
> +
> +    /* PCI bus */
> +    ppc460ex_pcie_init(env);
> +    /* FIXME: is this correct? */
> +    dev = sysbus_create_varargs("ppc440-pcix-host", 0xc0ec00000,
> +                                uic[1][0], uic[1][20], uic[1][21], uic[1][22],
> +                                NULL);
> +    pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
> +    if (!pci_bus) {
> +        error_report("couldn't create PCI controller!");
> +        exit(1);
> +    }
> +    memory_region_init_alias(isa, NULL, "isa_mmio", get_system_io(),
> +                             0, 0x10000);
> +    memory_region_add_subregion(get_system_memory(), 0xc08000000, isa);
> +
> +    /* PCI devices */
> +    pci_create_simple(pci_bus, PCI_DEVFN(6, 0), "sm501");
> +    /* SoC has a single SATA port but we don't emulate that yet
> +     * However, firmware and usual clients have driver for SiI311x
> +     * so add one for convenience by default */
> +    if (defaults_enabled()) {
> +        pci_create_simple(pci_bus, -1, "sii3112");
> +    }
> +
> +    /* SoC has 4 UARTs
> +     * but board has only one wired and two are present in fdt */
> +    if (serial_hds[0] != NULL) {
> +        serial_mm_init(address_space_mem, 0x4ef600300, 0, uic[1][1],
> +                       PPC_SERIAL_MM_BAUDBASE, serial_hds[0],
> +                       DEVICE_BIG_ENDIAN);
> +    }
> +    if (serial_hds[1] != NULL) {
> +        serial_mm_init(address_space_mem, 0x4ef600400, 0, uic[0][1],
> +                       PPC_SERIAL_MM_BAUDBASE, serial_hds[1],
> +                       DEVICE_BIG_ENDIAN);
> +    }
> +
> +    /* Load U-Boot image. */
> +    if (!machine->kernel_filename) {
> +        success = sam460ex_load_uboot();
> +        if (success < 0) {
> +            error_report("qemu: could not load firmware");
> +            exit(1);
> +        }
> +    }
> +
> +    /* Load kernel. */
> +    if (machine->kernel_filename) {
> +        success = load_uimage(machine->kernel_filename, &entry, &loadaddr,
> +                              NULL, NULL, NULL);
> +        if (success < 0) {
> +            uint64_t elf_entry, elf_lowaddr;
> +
> +            success = load_elf(machine->kernel_filename, NULL, NULL, &elf_entry,
> +                               &elf_lowaddr, NULL, 1, PPC_ELF_MACHINE, 0, 0);
> +            entry = elf_entry;
> +            loadaddr = elf_lowaddr;
> +        }
> +        /* XXX try again as binary */
> +        if (success < 0) {
> +            error_report("qemu: could not load kernel '%s'",
> +                    machine->kernel_filename);
> +            exit(1);
> +        }
> +    }
> +
> +    /* Load initrd. */
> +    if (machine->initrd_filename) {
> +        initrd_size = load_image_targphys(machine->initrd_filename,
> +                                          RAMDISK_ADDR,
> +                                          machine->ram_size - RAMDISK_ADDR);
> +        if (initrd_size < 0) {
> +            error_report("qemu: could not load ram disk '%s' at %x",
> +                    machine->initrd_filename, RAMDISK_ADDR);
> +            exit(1);
> +        }
> +    }
> +
> +    /* If we're loading a kernel directly, we must load the device tree too. */
> +    if (machine->kernel_filename) {
> +        int dt_size;
> +
> +        dt_size = sam460ex_load_device_tree(FDT_ADDR, machine->ram_size,
> +                                    RAMDISK_ADDR, initrd_size,
> +                                    machine->kernel_cmdline);
> +        if (dt_size < 0) {
> +            error_report("couldn't load device tree");
> +            exit(1);
> +        }
> +
> +        boot_info->dt_base = FDT_ADDR;
> +        boot_info->dt_size = dt_size;
> +    }
> +
> +    boot_info->entry = entry;
> +}
> +
> +static void sam460ex_machine_init(MachineClass *mc)
> +{
> +    mc->desc = "aCube Sam460ex";
> +    mc->init = sam460ex_init;
> +    mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("460exb");
> +    mc->default_ram_size = 512 * M_BYTE;
> +}
> +
> +DEFINE_MACHINE("sam460ex", sam460ex_machine_init)

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH v2 0/3] Sam460ex emulation
  2018-02-15 21:27 [Qemu-devel] [PATCH v2 0/3] Sam460ex emulation BALATON Zoltan
                   ` (2 preceding siblings ...)
  2018-02-15 21:27 ` [Qemu-devel] [PATCH v2 2/3] ppc440: Add emulation of plb-pcix controller found in some 440 SoCs BALATON Zoltan
@ 2018-02-16  6:50 ` Thomas Huth
  2018-02-16 10:55   ` BALATON Zoltan
  2018-06-21 21:15 ` [Qemu-devel] [v2,0/3] " Guenter Roeck
  4 siblings, 1 reply; 16+ messages in thread
From: Thomas Huth @ 2018-02-16  6:50 UTC (permalink / raw)
  To: BALATON Zoltan, qemu-devel, qemu-ppc; +Cc: Francois Revol, David Gibson

On 15.02.2018 22:27, BALATON Zoltan wrote:
> Remaining patches for Sam460ex emulation. The original cover letter
> with more details is here:
> 
> http://lists.nongnu.org/archive/html/qemu-ppc/2017-08/msg00112.html
> 
> We'll need to also add binaries for firmware (customised u-boot
> version) and dtb but I'm not sure how to submit those.

For the dtb, I think you could simply provide a patch that adds the dts
file to the pc-bios directory and another one that adds the dtb. Just
like it is already done with pc-bios/bamboo.dts / pc-bios/bamboo.dtb.

For u-boot, can you use the same upstream level as e500 ? I.e. check
whether "git submodule status roms/u-boot" is fine for you? If that's
ok, just do a "git submodule update roms/u-boot" and build uboot from
that directory - you then can submit a binary patch with that file for
pc-bios, too.

In case you need another u-boot version, I think you've got to update
the submodule to the newer upstream version first, and then also rebuild
the e500 binary... Cumbersome, but that's necessary since we've got to
ship the u-boot sources in the QEMU release tarballs, too, to be
compliant with the GPL.

 Thomas

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH v2 3/3] ppc: Add aCube Sam460ex board
  2018-02-16  3:10   ` David Gibson
@ 2018-02-16 10:45     ` BALATON Zoltan
  2018-02-17 23:48       ` BALATON Zoltan
  0 siblings, 1 reply; 16+ messages in thread
From: BALATON Zoltan @ 2018-02-16 10:45 UTC (permalink / raw)
  To: David Gibson; +Cc: Francois Revol, qemu-ppc, qemu-devel

On Fri, 16 Feb 2018, David Gibson wrote:
> On Thu, Feb 15, 2018 at 10:27:06PM +0100, BALATON Zoltan wrote:
>> Add emulation of aCube Sam460ex board based on AMCC 460EX embedded SoC.
>> This is not a complete implementation yet with a lot of components
>> still missing but enough for the U-Boot firmware to start and to boot
>> a Linux kernel or AROS.
>>
>> Signed-off-by: François Revol <revol@free.fr>
>> Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
>> ---
>>
>> v2:
>> - Rebased to latest changes on master
>> - Replaced printfs with error_report
>
> This has a conflict in hw/ppc/Makefile.objs.  Looks like it was based
> on some other patch that added ppc440_pcix.o.  That's not there
> upstream.

That's patch 2/3 of this series. Have you missed that?

Regards,
BALATON Zoltan

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH v2 0/3] Sam460ex emulation
  2018-02-16  6:50 ` [Qemu-devel] [Qemu-ppc] [PATCH v2 0/3] Sam460ex emulation Thomas Huth
@ 2018-02-16 10:55   ` BALATON Zoltan
  2018-02-16 23:07     ` Thomas Huth
  0 siblings, 1 reply; 16+ messages in thread
From: BALATON Zoltan @ 2018-02-16 10:55 UTC (permalink / raw)
  To: Thomas Huth; +Cc: qemu-devel, qemu-ppc, Francois Revol, David Gibson

On Fri, 16 Feb 2018, Thomas Huth wrote:
> On 15.02.2018 22:27, BALATON Zoltan wrote:
>> Remaining patches for Sam460ex emulation. The original cover letter
>> with more details is here:
>>
>> http://lists.nongnu.org/archive/html/qemu-ppc/2017-08/msg00112.html
>>
>> We'll need to also add binaries for firmware (customised u-boot
>> version) and dtb but I'm not sure how to submit those.
>
> For the dtb, I think you could simply provide a patch that adds the dts
> file to the pc-bios directory and another one that adds the dtb. Just
> like it is already done with pc-bios/bamboo.dts / pc-bios/bamboo.dtb.

OK thanks, I'll do that. Does it have to be two separate patches?

> For u-boot, can you use the same upstream level as e500 ? I.e. check
> whether "git submodule status roms/u-boot" is fine for you? If that's
> ok, just do a "git submodule update roms/u-boot" and build uboot from
> that directory - you then can submit a binary patch with that file for
> pc-bios, too.
>
> In case you need another u-boot version, I think you've got to update
> the submodule to the newer upstream version first, and then also rebuild
> the e500 binary... Cumbersome, but that's necessary since we've got to
> ship the u-boot sources in the QEMU release tarballs, too, to be
> compliant with the GPL.

Unfortunately we can't use the same u-boot as e500 because this board uses 
a forked and patched version which is not in upstream u-boot and upstream 
u-boot has even dropped support for this CPU in latest version so we 
actually need an older version (with patches) and not a newer one.

Therefore, it needs to be a binary built from a separate source so I think 
a new submodule will need to be added for this. How to do that? Where to 
host this git repo? Should I put it on github and refer to that as an 
external repo or should it be hosted in qemu repo somehow?

Regards,
BALATON Zoltan

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH v2 0/3] Sam460ex emulation
  2018-02-16 10:55   ` BALATON Zoltan
@ 2018-02-16 23:07     ` Thomas Huth
  2018-02-17  9:24       ` BALATON Zoltan
  2018-02-19  2:19       ` David Gibson
  0 siblings, 2 replies; 16+ messages in thread
From: Thomas Huth @ 2018-02-16 23:07 UTC (permalink / raw)
  To: BALATON Zoltan
  Cc: Francois Revol, qemu-ppc, qemu-devel, David Gibson, Jeff Cody,
	Stefan Hajnoczi

On 16.02.2018 11:55, BALATON Zoltan wrote:
> On Fri, 16 Feb 2018, Thomas Huth wrote:
>> On 15.02.2018 22:27, BALATON Zoltan wrote:
>>> Remaining patches for Sam460ex emulation. The original cover letter
>>> with more details is here:
>>>
>>> http://lists.nongnu.org/archive/html/qemu-ppc/2017-08/msg00112.html
>>>
>>> We'll need to also add binaries for firmware (customised u-boot
>>> version) and dtb but I'm not sure how to submit those.
>>
>> For the dtb, I think you could simply provide a patch that adds the dts
>> file to the pc-bios directory and another one that adds the dtb. Just
>> like it is already done with pc-bios/bamboo.dts / pc-bios/bamboo.dtb.
> 
> OK thanks, I'll do that. Does it have to be two separate patches?

I don't think so, I just thought that would be cleaner ... but one patch
should be fine, too, I guess. David?

>> For u-boot, can you use the same upstream level as e500 ? I.e. check
>> whether "git submodule status roms/u-boot" is fine for you? If that's
>> ok, just do a "git submodule update roms/u-boot" and build uboot from
>> that directory - you then can submit a binary patch with that file for
>> pc-bios, too.
>>
>> In case you need another u-boot version, I think you've got to update
>> the submodule to the newer upstream version first, and then also rebuild
>> the e500 binary... Cumbersome, but that's necessary since we've got to
>> ship the u-boot sources in the QEMU release tarballs, too, to be
>> compliant with the GPL.
> 
> Unfortunately we can't use the same u-boot as e500 because this board
> uses a forked and patched version which is not in upstream u-boot and
> upstream u-boot has even dropped support for this CPU in latest version
> so we actually need an older version (with patches) and not a newer one.

That's very unfortunate ... any chance that you could try to get that
CPU activated in upstream u-boot again and get the patches included there?

> Therefore, it needs to be a binary built from a separate source so I
> think a new submodule will need to be added for this. How to do that?
> Where to host this git repo? Should I put it on github and refer to that
> as an external repo or should it be hosted in qemu repo somehow?

No clue ... adding Stefan and Jeff to CC:, maybe they can recommend
something here.

 Thomas

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH v2 0/3] Sam460ex emulation
  2018-02-16 23:07     ` Thomas Huth
@ 2018-02-17  9:24       ` BALATON Zoltan
  2018-02-19  2:19       ` David Gibson
  1 sibling, 0 replies; 16+ messages in thread
From: BALATON Zoltan @ 2018-02-17  9:24 UTC (permalink / raw)
  To: Thomas Huth
  Cc: Francois Revol, qemu-ppc, qemu-devel, David Gibson, Jeff Cody,
	Stefan Hajnoczi

On Sat, 17 Feb 2018, Thomas Huth wrote:
> On 16.02.2018 11:55, BALATON Zoltan wrote:
>> On Fri, 16 Feb 2018, Thomas Huth wrote:
>>> On 15.02.2018 22:27, BALATON Zoltan wrote:
>>>> Remaining patches for Sam460ex emulation. The original cover letter
>>>> with more details is here:
>>>>
>>>> http://lists.nongnu.org/archive/html/qemu-ppc/2017-08/msg00112.html
>>>>
>>>> We'll need to also add binaries for firmware (customised u-boot
>>>> version) and dtb but I'm not sure how to submit those.
>>>
>>> For the dtb, I think you could simply provide a patch that adds the dts
>>> file to the pc-bios directory and another one that adds the dtb. Just
>>> like it is already done with pc-bios/bamboo.dts / pc-bios/bamboo.dtb.
>>
>> OK thanks, I'll do that. Does it have to be two separate patches?
>
> I don't think so, I just thought that would be cleaner ... but one patch
> should be fine, too, I guess. David?
>
>>> For u-boot, can you use the same upstream level as e500 ? I.e. check
>>> whether "git submodule status roms/u-boot" is fine for you? If that's
>>> ok, just do a "git submodule update roms/u-boot" and build uboot from
>>> that directory - you then can submit a binary patch with that file for
>>> pc-bios, too.
>>>
>>> In case you need another u-boot version, I think you've got to update
>>> the submodule to the newer upstream version first, and then also rebuild
>>> the e500 binary... Cumbersome, but that's necessary since we've got to
>>> ship the u-boot sources in the QEMU release tarballs, too, to be
>>> compliant with the GPL.
>>
>> Unfortunately we can't use the same u-boot as e500 because this board
>> uses a forked and patched version which is not in upstream u-boot and
>> upstream u-boot has even dropped support for this CPU in latest version
>> so we actually need an older version (with patches) and not a newer one.
>
> That's very unfortunate ... any chance that you could try to get that
> CPU activated in upstream u-boot again and get the patches included there?

Not likely because it was removed to simplify code and get rid of 
unmaintained CPUs. Also the hardware vendor never upstreamed the board 
code which only exists in their sources, but these u-boot modifications 
are needed for boot loaders running on the hardware so we cannot use stock 
u-boot if we want to boot usual OSes which we want as that's the 
interesting part of this hardware.

Regards,
BALATON Zoltan

>> Therefore, it needs to be a binary built from a separate source so I
>> think a new submodule will need to be added for this. How to do that?
>> Where to host this git repo? Should I put it on github and refer to that
>> as an external repo or should it be hosted in qemu repo somehow?
>
> No clue ... adding Stefan and Jeff to CC:, maybe they can recommend
> something here.
>
> Thomas
>
>

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH v2 3/3] ppc: Add aCube Sam460ex board
  2018-02-16 10:45     ` [Qemu-devel] [Qemu-ppc] " BALATON Zoltan
@ 2018-02-17 23:48       ` BALATON Zoltan
  2018-02-19  2:06         ` David Gibson
  0 siblings, 1 reply; 16+ messages in thread
From: BALATON Zoltan @ 2018-02-17 23:48 UTC (permalink / raw)
  To: David Gibson; +Cc: Francois Revol, qemu-ppc, qemu-devel

On Fri, 16 Feb 2018, BALATON Zoltan wrote:
> On Fri, 16 Feb 2018, David Gibson wrote:
>> On Thu, Feb 15, 2018 at 10:27:06PM +0100, BALATON Zoltan wrote:
>>> Add emulation of aCube Sam460ex board based on AMCC 460EX embedded SoC.
>>> This is not a complete implementation yet with a lot of components
>>> still missing but enough for the U-Boot firmware to start and to boot
>>> a Linux kernel or AROS.
>>> 
>>> Signed-off-by: François Revol <revol@free.fr>
>>> Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
>>> ---
>>> 
>>> v2:
>>> - Rebased to latest changes on master
>>> - Replaced printfs with error_report
>> 
>> This has a conflict in hw/ppc/Makefile.objs.  Looks like it was based
>> on some other patch that added ppc440_pcix.o.  That's not there
>> upstream.
>
> That's patch 2/3 of this series. Have you missed that?

I've sent a v3 for this patch (3/3) now:

http://lists.nongnu.org/archive/html/qemu-devel/2018-02/msg04774.html

which includes the dts and dtb as well (I'll send a separate patch for the 
firmware after we agree on how to best do that). The missing 2/3 of the v2 
series is still valid and needed before this new patch:

http://lists.nongnu.org/archive/html/qemu-devel/2018-02/msg04259.html

The v3 is only replacing 3/3 of the previous series. Hope this is not too 
confusing.

Regards,
BALATON Zoltan

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH v2 3/3] ppc: Add aCube Sam460ex board
  2018-02-17 23:48       ` BALATON Zoltan
@ 2018-02-19  2:06         ` David Gibson
  2018-02-19 10:45           ` BALATON Zoltan
  0 siblings, 1 reply; 16+ messages in thread
From: David Gibson @ 2018-02-19  2:06 UTC (permalink / raw)
  To: BALATON Zoltan; +Cc: Francois Revol, qemu-ppc, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 1921 bytes --]

On Sun, Feb 18, 2018 at 12:48:27AM +0100, BALATON Zoltan wrote:
> On Fri, 16 Feb 2018, BALATON Zoltan wrote:
> > On Fri, 16 Feb 2018, David Gibson wrote:
> > > On Thu, Feb 15, 2018 at 10:27:06PM +0100, BALATON Zoltan wrote:
> > > > Add emulation of aCube Sam460ex board based on AMCC 460EX embedded SoC.
> > > > This is not a complete implementation yet with a lot of components
> > > > still missing but enough for the U-Boot firmware to start and to boot
> > > > a Linux kernel or AROS.
> > > > 
> > > > Signed-off-by: François Revol <revol@free.fr>
> > > > Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
> > > > ---
> > > > 
> > > > v2:
> > > > - Rebased to latest changes on master
> > > > - Replaced printfs with error_report
> > > 
> > > This has a conflict in hw/ppc/Makefile.objs.  Looks like it was based
> > > on some other patch that added ppc440_pcix.o.  That's not there
> > > upstream.
> > 
> > That's patch 2/3 of this series. Have you missed that?
> 
> I've sent a v3 for this patch (3/3) now:
> 
> http://lists.nongnu.org/archive/html/qemu-devel/2018-02/msg04774.html
> 
> which includes the dts and dtb as well (I'll send a separate patch for the
> firmware after we agree on how to best do that). The missing 2/3 of the v2
> series is still valid and needed before this new patch:
> 
> http://lists.nongnu.org/archive/html/qemu-devel/2018-02/msg04259.html
> 
> The v3 is only replacing 3/3 of the previous series. Hope this is not too
> confusing.

Uh.. it's a bit awkward.  Especially since I do seem to have someone
mislaid the earlier 2/3.  Can you please resend with whatever's needed
on top of the current ppc-for-2.12.

> 
> Regards,
> BALATON Zoltan


-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH v2 0/3] Sam460ex emulation
  2018-02-16 23:07     ` Thomas Huth
  2018-02-17  9:24       ` BALATON Zoltan
@ 2018-02-19  2:19       ` David Gibson
  1 sibling, 0 replies; 16+ messages in thread
From: David Gibson @ 2018-02-19  2:19 UTC (permalink / raw)
  To: Thomas Huth
  Cc: BALATON Zoltan, Francois Revol, qemu-ppc, qemu-devel, Jeff Cody,
	Stefan Hajnoczi

[-- Attachment #1: Type: text/plain, Size: 2758 bytes --]

On Sat, Feb 17, 2018 at 12:07:34AM +0100, Thomas Huth wrote:
> On 16.02.2018 11:55, BALATON Zoltan wrote:
> > On Fri, 16 Feb 2018, Thomas Huth wrote:
> >> On 15.02.2018 22:27, BALATON Zoltan wrote:
> >>> Remaining patches for Sam460ex emulation. The original cover letter
> >>> with more details is here:
> >>>
> >>> http://lists.nongnu.org/archive/html/qemu-ppc/2017-08/msg00112.html
> >>>
> >>> We'll need to also add binaries for firmware (customised u-boot
> >>> version) and dtb but I'm not sure how to submit those.
> >>
> >> For the dtb, I think you could simply provide a patch that adds the dts
> >> file to the pc-bios directory and another one that adds the dtb. Just
> >> like it is already done with pc-bios/bamboo.dts / pc-bios/bamboo.dtb.
> > 
> > OK thanks, I'll do that. Does it have to be two separate patches?
> 
> I don't think so, I just thought that would be cleaner ... but one patch
> should be fine, too, I guess. David?

I'd actually prefer them both in one patch.

> 
> >> For u-boot, can you use the same upstream level as e500 ? I.e. check
> >> whether "git submodule status roms/u-boot" is fine for you? If that's
> >> ok, just do a "git submodule update roms/u-boot" and build uboot from
> >> that directory - you then can submit a binary patch with that file for
> >> pc-bios, too.
> >>
> >> In case you need another u-boot version, I think you've got to update
> >> the submodule to the newer upstream version first, and then also rebuild
> >> the e500 binary... Cumbersome, but that's necessary since we've got to
> >> ship the u-boot sources in the QEMU release tarballs, too, to be
> >> compliant with the GPL.
> > 
> > Unfortunately we can't use the same u-boot as e500 because this board
> > uses a forked and patched version which is not in upstream u-boot and
> > upstream u-boot has even dropped support for this CPU in latest version
> > so we actually need an older version (with patches) and not a newer one.
> 
> That's very unfortunate ... any chance that you could try to get that
> CPU activated in upstream u-boot again and get the patches included there?
> 
> > Therefore, it needs to be a binary built from a separate source so I
> > think a new submodule will need to be added for this. How to do that?
> > Where to host this git repo? Should I put it on github and refer to that
> > as an external repo or should it be hosted in qemu repo somehow?
> 
> No clue ... adding Stefan and Jeff to CC:, maybe they can recommend
> something here.
> 
>  Thomas
> 

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [Qemu-ppc] [PATCH v2 3/3] ppc: Add aCube Sam460ex board
  2018-02-19  2:06         ` David Gibson
@ 2018-02-19 10:45           ` BALATON Zoltan
  0 siblings, 0 replies; 16+ messages in thread
From: BALATON Zoltan @ 2018-02-19 10:45 UTC (permalink / raw)
  To: David Gibson; +Cc: Francois Revol, qemu-ppc, qemu-devel

On Mon, 19 Feb 2018, David Gibson wrote:
> On Sun, Feb 18, 2018 at 12:48:27AM +0100, BALATON Zoltan wrote:
>> On Fri, 16 Feb 2018, BALATON Zoltan wrote:
>>> On Fri, 16 Feb 2018, David Gibson wrote:
>>>> On Thu, Feb 15, 2018 at 10:27:06PM +0100, BALATON Zoltan wrote:
>>>>> Add emulation of aCube Sam460ex board based on AMCC 460EX embedded SoC.
>>>>> This is not a complete implementation yet with a lot of components
>>>>> still missing but enough for the U-Boot firmware to start and to boot
>>>>> a Linux kernel or AROS.
>>>>>
>>>>> Signed-off-by: François Revol <revol@free.fr>
>>>>> Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
>>>>> ---
>>>>>
>>>>> v2:
>>>>> - Rebased to latest changes on master
>>>>> - Replaced printfs with error_report
>>>>
>>>> This has a conflict in hw/ppc/Makefile.objs.  Looks like it was based
>>>> on some other patch that added ppc440_pcix.o.  That's not there
>>>> upstream.
>>>
>>> That's patch 2/3 of this series. Have you missed that?
>>
>> I've sent a v3 for this patch (3/3) now:
>>
>> http://lists.nongnu.org/archive/html/qemu-devel/2018-02/msg04774.html
>>
>> which includes the dts and dtb as well (I'll send a separate patch for the
>> firmware after we agree on how to best do that). The missing 2/3 of the v2
>> series is still valid and needed before this new patch:
>>
>> http://lists.nongnu.org/archive/html/qemu-devel/2018-02/msg04259.html
>>
>> The v3 is only replacing 3/3 of the previous series. Hope this is not too
>> confusing.
>
> Uh.. it's a bit awkward.  Especially since I do seem to have someone
> mislaid the earlier 2/3.  Can you please resend with whatever's needed
> on top of the current ppc-for-2.12.

No problem, sent it now.

Regards,
BALATON Zoltan

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [Qemu-devel] [v2,0/3] Sam460ex emulation
  2018-02-15 21:27 [Qemu-devel] [PATCH v2 0/3] Sam460ex emulation BALATON Zoltan
                   ` (3 preceding siblings ...)
  2018-02-16  6:50 ` [Qemu-devel] [Qemu-ppc] [PATCH v2 0/3] Sam460ex emulation Thomas Huth
@ 2018-06-21 21:15 ` Guenter Roeck
  4 siblings, 0 replies; 16+ messages in thread
From: Guenter Roeck @ 2018-06-21 21:15 UTC (permalink / raw)
  To: BALATON Zoltan
  Cc: qemu-devel, qemu-ppc, Francois Revol, Alexander Graf, David Gibson

Hi,

On Thu, Feb 15, 2018 at 10:27:06PM +0100, BALATON Zoltan wrote:
> Remaining patches for Sam460ex emulation. The original cover letter
> with more details is here:
> 
> http://lists.nongnu.org/archive/html/qemu-ppc/2017-08/msg00112.html
> 
> We'll need to also add binaries for firmware (customised u-boot
> version) and dtb but I'm not sure how to submit those.
> 
> Current status for OSes I've tried:
> 
> - AROS boots (after I've fixed some bugs in it which are now upstream
>   so the nightly iso should work) but keyboard doesn't work (could be
>   a bug in AROS's HID driver) and time is going slow (this can be seen
>   in time prefs). This may be a QEMU bug and possibly causes the hang
>   seen in other OSes but I don't know what causes it or how to fix it.
>   Maybe related to some internal timing registers of the SoC because
>   setting multipliers to real values causes U-Boot to become slow.
>   Anyone with more knowledge of this hardware has any idea?
> 
> - Linux: kernel boots but hangs during user space (again could be the
>   above timing problem or maybe missing emac network interface
>   emulation but I don't really know).
> 
I played with the sam460ex emulation under Linux. There are two problems:

- qemu does not emulate "ibm,cpm". If specified in the devicetree file,
  Linux tries to access the respective dcr register (0x160) and crashes.
- If the kernel is loaded with "-kernel" and there is no uboot, the serial
  port frequency is set to 0, and the serial ports fail to initialize.
  As result, there is no serial port output from userspace. Userspace runs,
  but is silent.

Both problems are easy to fix with a separate devicetree file.

Guenter

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2018-06-21 21:15 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-02-15 21:27 [Qemu-devel] [PATCH v2 0/3] Sam460ex emulation BALATON Zoltan
2018-02-15 21:27 ` [Qemu-devel] [PATCH v2 1/3] ppc4xx: Add device models found in PPC440 core SoCs BALATON Zoltan
2018-02-16  3:06   ` David Gibson
2018-02-15 21:27 ` [Qemu-devel] [PATCH v2 3/3] ppc: Add aCube Sam460ex board BALATON Zoltan
2018-02-16  3:10   ` David Gibson
2018-02-16 10:45     ` [Qemu-devel] [Qemu-ppc] " BALATON Zoltan
2018-02-17 23:48       ` BALATON Zoltan
2018-02-19  2:06         ` David Gibson
2018-02-19 10:45           ` BALATON Zoltan
2018-02-15 21:27 ` [Qemu-devel] [PATCH v2 2/3] ppc440: Add emulation of plb-pcix controller found in some 440 SoCs BALATON Zoltan
2018-02-16  6:50 ` [Qemu-devel] [Qemu-ppc] [PATCH v2 0/3] Sam460ex emulation Thomas Huth
2018-02-16 10:55   ` BALATON Zoltan
2018-02-16 23:07     ` Thomas Huth
2018-02-17  9:24       ` BALATON Zoltan
2018-02-19  2:19       ` David Gibson
2018-06-21 21:15 ` [Qemu-devel] [v2,0/3] " Guenter Roeck

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.