From: Michael Davidsaver <mdavidsaver@gmail.com>
To: Alexander Graf <agraf@suse.de>,
David Gibson <david@gibson.dropbear.id.au>,
qemu-ppc@nongnu.org
Cc: qemu-devel@nongnu.org, Michael Davidsaver <mdavidsaver@gmail.com>
Subject: [Qemu-devel] [PATCH 11/12] ppc: add mvme3100 machine
Date: Sun, 19 Nov 2017 21:24:19 -0600 [thread overview]
Message-ID: <20171120032420.9134-12-mdavidsaver@gmail.com> (raw)
In-Reply-To: <20171120032420.9134-1-mdavidsaver@gmail.com>
Signed-off-by: Michael Davidsaver <mdavidsaver@gmail.com>
---
hw/ppc/Makefile.objs | 1 +
hw/ppc/mvme3100.c | 688 +++++++++++++++++++++++++++++++++++++++++++++++++
hw/ppc/mvme3100_cpld.c | 192 ++++++++++++++
3 files changed, 881 insertions(+)
create mode 100644 hw/ppc/mvme3100.c
create mode 100644 hw/ppc/mvme3100_cpld.c
diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs
index c1a63d0c39..c1118aaa42 100644
--- a/hw/ppc/Makefile.objs
+++ b/hw/ppc/Makefile.objs
@@ -26,5 +26,6 @@ obj-$(CONFIG_MAC) += mac_newworld.o
obj-$(CONFIG_E500) += e500.o mpc8544ds.o e500plat.o
obj-$(CONFIG_E500) += ppce500_spin.o
obj-$(CONFIG_E500) += e500_ccsr.o
+obj-$(CONFIG_E500) += mvme3100.o mvme3100_cpld.o
# PowerPC 440 Xilinx ML507 reference board.
obj-$(CONFIG_XILINX) += virtex_ml507.o
diff --git a/hw/ppc/mvme3100.c b/hw/ppc/mvme3100.c
new file mode 100644
index 0000000000..2e6d428533
--- /dev/null
+++ b/hw/ppc/mvme3100.c
@@ -0,0 +1,688 @@
+/*
+ * MVME3100 board emulation
+ *
+ * Copyright (c) 2015 Michael Davidsaver
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the LICENSE file in the top-level directory.
+ *
+ * This model was developed according to the
+ * MVME3100 Single Board Computer Programmer's Reference
+ * P/N: 6806800G37B
+ * July 2014
+ *
+ * mvme3100-1152
+ * 677MHz core, 256MB ram, 64MB flash
+ * mvme3100-1263
+ * 833MHz core, 512MB ram, 128MB flash
+ *
+ * MOTLoad on mvme3100-1152 says:
+ * MPU-Type =MPC8540
+ * MPU-Int Clock Speed =666MHz
+ * MPU-CCB Clock Speed =333MHz
+ * MPU-DDR Clock Speed =166MHz
+ * MPU-PCI Clock Speed =66MHz, PCI, 64-bit
+ * MPU-Int Cache(L2) Enabled, 256KB, L2CTL =A8000300
+ * Reset/Boot Vector =Flash0
+ * Local Memory Found =10000000 (&268435456)
+ *
+ * MOTLoad on mvme3100-1263 says:
+ * MPU-Type =MPC8540
+ * MPU-Int Clock Speed =833MHz
+ * MPU-CCB Clock Speed =333MHz
+ * MPU-DDR Clock Speed =166MHz
+ * MPU-PCI Clock Speed =66MHz, PCI, 64-bit
+ * MPU-Int Cache(L2) Enabled, 256KB, L2CTL =A8000300
+ * Reset/Boot Vector =Flash0
+ * Local Memory Found =20000000 (&536870912)
+ *
+ * Clock ratios
+ * CCB/PCI -> 5/1
+ * core/CCB -> 2/1 (-1152)
+ * -> 5/2 (-1263)
+ *
+ * The overall memory map is determined by the Local Address Windows.
+ * We do not model the LAWs explicitly.
+ *
+ * MOTLoad configures as follows (a super set of table 1-4)
+ * (MOTLoad RTOS Version 2.0, PAL Version 1.2 RM04)
+ * LAW 0, 7 - disabled
+ * LAW 1 - 0x00000000 -> 0x7fffffff - RAM 2G
+ * LAW 2 - 0x80000000 -> 0xbfffffff - PCI 1G
+ * LAW 3 - 0xc0000000 -> 0xdfffffff - PCI 512MB
+ * LAW 4 - 0xe0000000 -> 0xe0ffffff - PCI 16MB
+ * gap - 0xe1000000 -> 0xbfffffff - CCSR @ 0xe1000000
+ * LAW 5 - 0xe2000000 -> 0xe2ffffff - LBC 16MB
+ * gap - 0xe3000000 -> 0xefffffff
+ * LAW 6 - 0xf0000000 -> 0xffffffff - LBC 256MB
+ *
+ * And validated against the RTEMS 4.9.6 mvme3100 BSP
+ */
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qapi/error.h"
+#include "qapi/visitor.h"
+#include "e500.h"
+#include "cpu.h"
+#include "qemu-common.h"
+#include "cpu-qom.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/dma.h"
+#include "sysemu/block-backend.h"
+#include "hw/loader.h"
+#include "hw/pci/pci.h"
+#include "hw/boards.h"
+#include "hw/ppc/ppc.h"
+#include "hw/net/fsl_etsec/etsec.h"
+#include "sysemu/device_tree.h"
+#include "sysemu/qtest.h"
+#include "hw/ppc/openpic.h"
+#include "qemu/error-report.h"
+
+/* Same as prep.c and other PPC boards */
+#define CFG_ADDR 0xf0000510
+
+#define TYPE_MVME3100 MACHINE_TYPE_NAME("mvme3100")
+#define MVME3100(obj) OBJECT_CHECK(MVME3100State, (obj), TYPE_MVME3100)
+#define MVME3100_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(MVME3100Class, (obj), TYPE_MVME3100)
+#define MVME3100_CLASS(klass) \
+ OBJECT_CLASS_CHECK(MVME3100Class, (klass), TYPE_MVME3100)
+
+
+typedef struct mvme3100_info {
+ const char *desc;
+ uint32_t cpu_freq;
+ uint32_t porpllsr;
+ uint32_t ram_size;
+} mvme3100_info;
+
+typedef struct MVME3100Class {
+ /*< private >*/
+ MachineClass parent_class;
+ /*< public >*/
+
+ const mvme3100_info *info;
+} MVME3100Class;
+
+typedef struct MVME3100State {
+ /*< private >*/
+ MachineState parent_obj;
+ /*< public >*/
+
+ uint32_t load_address,
+ entry_address;
+} MVME3100State;
+
+
+/* motload "global environment" variables */
+static
+const char *gev[] = {
+ /* TODO: somehow snoop in slirp_instances to pick up IP config? */
+ "mot-/dev/enet0-cipa=10.0.2.15",
+ "mot-/dev/enet0-gipa=10.0.2.2",
+ "mot-/dev/enet0-snma=255.255.255.0",
+ "mot-/dev/enet0-sipa=10.0.2.2",
+ /* RTEMS specific names for things motload doesn't have */
+ "rtems-dns-server=10.0.2.3",
+ "rtems-client-name=qemu",
+ NULL,
+};
+
+/* Prepare Motorola Vital Product Data eeprom image.
+ * Provided to bootloader for use as a default.
+ *
+ * Begins with constant "MOTLOAD" followed by variable length records
+ * with a two byte header (ID code then body length in bytes).
+ *
+ * | ID | Length | body .... | repeated until ID=0xFF
+ *
+ * ID Codes:
+ * 1 - Product ID (string)
+ * 2 - Assembly # (string)
+ * 3 - Serial # (string)
+ * 5 - CPU Speed (Hz, 4 byte integer + 1 nil)
+ * 6 - Bus Speed (Hz, 4 byte integer + 1 nil)
+ * 8 - Ethernet MAC (6 bytes + 1 nil)
+ * 9 - CPU type
+ * A - VPD CRC (4 bytes)
+ * B - Flash Config (??)
+ * E - L2 Cache Config (??)
+ * F - VPD Version (4 bytes)
+ * 19 - L3 Cache Config (??)
+ * FF - End of VPD (size zero)
+ *
+ * Repeat entries for repeated units. eg. two ID=0x8 for two NICs
+ *
+ * MOTLoad uses the same eeprom to hold it's user configuration
+ * Global Environment Variable (GEV) list.
+ */
+typedef struct vpdeeprom {
+ char * const base;
+ char *cur;
+ size_t total;
+} vpdeeprom;
+
+static
+void append_gev_vpd(vpdeeprom *vpd, const char *str)
+{
+ const size_t remaining = vpd->total - (vpd->cur - vpd->base),
+ len = strlen(str);
+
+ if ((len == 0 && remaining < 1)
+ || (remaining < len + 2))
+ {
+ fprintf(stderr, "VPD GEV overflow\n");
+ return;
+ }
+
+ memcpy(vpd->cur, str, len + 1);
+
+ vpd->cur += len + 1;
+}
+
+static
+void append_vpd(vpdeeprom *vpd, uint8_t id, size_t cnt, const void *val)
+{
+ const size_t remaining = vpd->total - (vpd->cur - vpd->base);
+
+ /* must have enough space for this entry and final ID=0xff */
+ if ((id == 0xff && remaining < 2)
+ || (remaining + 4 < cnt || cnt > 255))
+ {
+ fprintf(stderr, "VPD overflow\n");
+ return;
+ }
+
+ vpd->cur[0] = id;
+ vpd->cur[1] = cnt;
+ memcpy(vpd->cur + 2, val, cnt);
+
+ vpd->cur += 2 + cnt;
+}
+
+static
+void append_string_vpd(vpdeeprom *vpd, uint8_t id, const char *str)
+{
+ /* include trailing nil */
+ append_vpd(vpd, id, strlen(str) + 1, str);
+}
+
+static
+void append_mac_vpd(vpdeeprom *vpd, uint8_t id, const MACAddr *addr)
+{
+ char buf[7];
+ memcpy(buf, addr->a, 6);
+ buf[6] = 0;
+
+ append_vpd(vpd, id, 7, buf);
+}
+
+static
+void append_u32_vpd(vpdeeprom *vpd, uint8_t id, uint32_t val)
+{
+ union {
+ uint32_t ival;
+ char bytes[5]; /* include trailing nil */
+ } buf;
+ buf.ival = cpu_to_be32(val);
+ buf.bytes[4] = 0;
+
+ append_vpd(vpd, id, 5, buf.bytes);
+}
+
+static
+void build_vpd(const mvme3100_info *info, char *buf, size_t cnt,
+ const char *extra)
+{
+ vpdeeprom vpd = {buf, buf, cnt};
+ size_t i;
+
+ memset(buf, 0, cnt);
+
+ strcpy(buf, "MOTOROLA");
+ vpd.cur += 8;
+
+ /* Product ID (eg. "MVME3100-1152") */
+ append_string_vpd(&vpd, 1, info->desc);
+
+ /* serial number */
+ append_string_vpd(&vpd, 3, "E0120000");
+
+ /* CPU Freq. */
+ append_u32_vpd(&vpd, 5, info->cpu_freq);
+
+ /* PCI Bus Freq. */
+ append_u32_vpd(&vpd, 6, 66666666);
+
+ for (i = 0; i < MAX_NICS; i++) {
+ if (nd_table[i].used) {
+ append_mac_vpd(&vpd, 8, &nd_table[i].macaddr);
+ }
+ }
+
+ append_vpd(&vpd, 0xff, 0, NULL);
+
+ if (vpd.cur - vpd.base > 0x10f8) {
+ fprintf(stderr, "VPD overflows GEV area.\n");
+ return;
+ }
+
+ /* MOTLOAD's Global Environment Variables
+ * start at offset 0x10f8.
+ * This is a set of nil terminated strings of the form "name=value"
+ * with a zero length string signaling the end.
+ */
+ vpd.cur = vpd.base + 0x10f8;
+
+ for (i = 0; gev[i]; i++) {
+ append_gev_vpd(&vpd, gev[i]);
+ }
+
+ if (extra) {
+ char *E = g_strdup(extra);
+ char **opts = g_strsplit(E, " ", 0);
+ size_t i;
+
+ g_free(E);
+
+ for (i = 0; opts[i]; i++) {
+ char *opt = g_strstrip(opts[i]);
+ size_t olen = strlen(opt);
+
+ if (olen == 0) {
+ continue;
+ } else if (!strchr(opt, '=')) {
+ fprintf(stderr, "Missing '=' in -append %s\n", extra);
+ continue;
+ }
+
+ append_gev_vpd(&vpd, opt);
+ }
+
+ g_strfreev(opts);
+ }
+
+ /* zero length string signals end */
+ append_gev_vpd(&vpd, "");
+}
+
+static void mvme3100_fixup_devtree(PPCE500Params *params, void *fdt)
+{
+ (void)params;
+ (void)fdt;
+}
+
+static
+void set_map(CPUPPCState *env, unsigned way,
+ target_ulong va, hwaddr pa,
+ unsigned size)
+{
+ ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, way);
+
+ tlb->mas1 = MAS1_VALID | (size << MAS1_TSIZE_SHIFT);
+ tlb->mas2 = (va & TARGET_PAGE_MASK) | MAS2_I | MAS2_G;
+ tlb->mas7_3 = (pa & TARGET_PAGE_MASK) | MAS3_SR | MAS3_SW | MAS3_SX;
+}
+
+static
+void remap_tlb_bare(CPUPPCState *env)
+{
+ /* The MPC8540 ref. manual says only the upper 4KB (ROM)
+ * is mapped, but doesn't say exactly how this mapping
+ * is setup. So we arbitrarily decide to use TLB1 entry 0.
+ */
+ set_map(env, 0, 0xfffff000, 0xfffff000, 0x02);
+
+ env->tlb_dirty = true;
+}
+
+/* runs after ppce500_cpu_reset() */
+static void mvme3100_cpu_reset(void *opaque)
+{
+ PowerPCCPU *cpu = opaque;
+ CPUPPCState *env = &cpu->env;
+
+ /* We don't model HID0 functions.
+ * HID0[EMCP] (32) and HID0[TBEN] (TBEN) set
+ */
+ env->spr[SPR_HID0] = 0x80004000;
+
+ remap_tlb_bare(&cpu->env);
+ env->nip = 0xfffffffc;
+}
+
+/* PCI config from a real mvme3100 as configured by motload
+ *
+ * BUS:SLOT:FUN VENDOR-DEV_ID: COMMAND STATUS BASE_ADDR0 BASE_ADDR1 IRQ_PIN -> IRQ_LINE
+ * 0:0x00:0 0x1057-0x0008: 0x0006 0x20B0 0x80000000 0x00000000 0 -> 0 (=0x00)
+ * 0:0x11:0 0x10E3-0x0148: 0x0146 0x02B0 0x80100004 0x00000000 1 -> 0 (=0x00)
+ * 0:0x12:0 0x10B5-0x6520: 0x0147 0x02B0 0x00000000 0x00000000 0 -> 0 (=0x00)
+ * 0:0x13:0 0x10B5-0x6520: 0x0147 0x02B0 0x00000000 0x00000000 0 -> 0 (=0x00)
+ * 0:0x14:0 0x8086-0x3200: 0x0145 0x02B0 0x00012001 0x00013001 1 -> 2 (=0x02)
+ * 2:0x00:0 0x1033-0x0035: 0x0146 0x0210 0x80300000 0x00000000 1 -> 4 (=0x04)
+ * 2:0x00:1 0x1033-0x0035: 0x0146 0x0210 0x80301000 0x00000000 2 -> 5 (=0x05)
+ *
+ * The modeled PCI host bridge differs.
+ *
+ * We don't model:
+ * # The SATA controller GD31244 (0x8086-0x3200)
+ * # The USB (OHCI) controller uPD740101 (0x1033-0x0035)
+ *
+ * (Note that the SATA controller found on newer boards is different)
+ */
+
+static void mvme3100_init(MachineState *machine)
+{
+ /* Config based on system state from MOTLoad, not power on */
+ static
+ PPCE500Params params = {
+ .pci_first_slot = 0,
+ .pci_nr_slots = 5,
+ .fixup_devtree = mvme3100_fixup_devtree,
+ .mpic_version = OPENPIC_MODEL_FSL_MPIC_20,
+ .ccsrbar_base = 0xff700000ULL,
+ .pci_mmio_base = 0x80000000ULL,
+ .pci_mmio_bus_base = 0x80000000ULL,
+ .pci_pio_base = 0xE0000000ULL,
+ .spin_base = 0xE3000000ULL, /* not used */
+ .skip_load = 1,
+ .tsec_nic = true,
+ /* .porpllsr set from mvme3100_info */
+ /* Decrementor frequency actually controlled by HID0[SEL_TBCLK]
+ * or disabled by HID0[TBEN].
+ * We don't model and assume always enabled with CCB/8
+ */
+ .decrementor_freq = 41666666,
+ };
+ MVME3100State *mvme3100 = MVME3100(machine);
+ const mvme3100_info *info;
+ DeviceState *dev;
+ BusState *i2c;
+ SysBusDevice *cpld, *ccsr, *pic;
+ FWCfgState *fwinfo;
+ DriveInfo *drvinfo;
+
+ {
+ MVME3100Class *klass = MVME3100_GET_CLASS(machine);
+ info = klass->info;
+ }
+ params.porpllsr = info->porpllsr;
+
+ /* Setup CPU */
+ ppce500_init(machine, ¶ms);
+
+ qemu_register_reset(mvme3100_cpu_reset, POWERPC_CPU(first_cpu));
+
+ pic = SYS_BUS_DEVICE(object_resolve_path("/machine/pic", NULL));
+ ccsr = SYS_BUS_DEVICE(object_resolve_path("/machine/e500-ccsr", NULL));
+
+ /* Setup mvme3100 specific CPLD device */
+ cpld = SYS_BUS_DEVICE(qdev_create(NULL, "mvme3100-cpld"));
+ object_property_add_child(qdev_get_machine(), "cpld",
+ OBJECT(cpld), &error_fatal);
+ qdev_init_nofail(DEVICE(cpld));
+
+ memory_region_add_subregion(get_system_memory(),
+ 0xe2000000,
+ sysbus_mmio_get_region(cpld, 0));
+
+ fwinfo = fw_cfg_init_mem(CFG_ADDR, CFG_ADDR + 2);
+ fw_cfg_add_i16(fwinfo, FW_CFG_NB_CPUS, 1);
+ fw_cfg_add_i16(fwinfo, FW_CFG_MAX_CPUS, 1);
+ fw_cfg_add_i64(fwinfo, FW_CFG_RAM_SIZE, machine->ram_size);
+
+ /* I2C Controller */
+ dev = DEVICE(object_resolve_path("/machine/i2c[0]", NULL));
+ assert(dev);
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0,
+ qdev_get_gpio_in(DEVICE(pic), 16 + 27));
+ i2c = qdev_get_child_bus(dev, "bus");
+ assert(i2c);
+
+ dev = DEVICE(object_resolve_path("/machine/pci-host", NULL));
+ assert(dev);
+ /*TODO: add pci-to-pci bridge and fix host bridge IRQ mappings
+ * to start from IRQ4
+ */
+
+ /* NIC */
+ if (nd_table[0].used) {
+ qemu_check_nic_model(&nd_table[0], "eTSEC");
+
+ dev = etsec_create(0x24000,
+ sysbus_mmio_get_region(ccsr, 0),
+ &nd_table[0],
+ qdev_get_gpio_in(DEVICE(pic), 16 + 13),
+ qdev_get_gpio_in(DEVICE(pic), 16 + 14),
+ qdev_get_gpio_in(DEVICE(pic), 16 + 18));
+
+ } else if (nd_table[1].used) {
+ qemu_check_nic_model(&nd_table[1], "eTSEC");
+
+ dev = etsec_create(0x25000,
+ sysbus_mmio_get_region(ccsr, 0),
+ &nd_table[1],
+ sysbus_get_connected_irq(pic, 16 + 19),
+ sysbus_get_connected_irq(pic, 16 + 20),
+ sysbus_get_connected_irq(pic, 16 + 23));
+ }
+
+ /* VPD EEPROM */
+ dev = qdev_create(i2c, "at24c-eeprom");
+ object_property_add_child(qdev_get_machine(), "vpd", OBJECT(dev),
+ &error_fatal);
+ qdev_prop_set_uint8(dev, "address", 0xa8 >> 1);
+ qdev_prop_set_uint32(dev, "rom-size", 8192 * 8);
+
+ drvinfo = drive_get(IF_PFLASH, 0, 0);
+ if (drvinfo) {
+ qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(drvinfo),
+ &error_fatal);
+ }
+
+ qdev_init_nofail(dev);
+
+ {
+ char *buf;
+
+ buf = g_malloc0(8192 * 8);
+
+ build_vpd(info, buf, 8192 * 8, machine->kernel_cmdline);
+
+ fw_cfg_add_file(fwinfo, "tomload/vpd", buf, 8192 * 8);
+ }
+
+ /* DS1375 RTC */
+ dev = qdev_create(i2c, "ds1375");
+ object_property_add_child(qdev_get_machine(), "rtc", OBJECT(dev),
+ &error_fatal);
+ qdev_prop_set_uint8(dev, "address", 0xd0 >> 1);
+ qdev_init_nofail(dev);
+
+ /* TODO: unmodeled i2c devices.
+ * 0x90 - ds1621 temperature sensor
+ * 0xa0 - 256*8 byte DDR SPD (???)
+ * 0xa4 - 64k*8 byte eeprom for "user" configuration
+ * 0xa6 - 64k*8 byte eeprom for "user" configuration
+ * 0xaa - 8k*8 byte eeprom for VPD of rear expansion card
+ */
+
+ if (!bios_name) {
+ bios_name = "tomload.bin";
+ }
+
+ if (!qtest_enabled()) {
+ MemoryRegion *rom = g_malloc0(sizeof(*rom));
+ char *fullname = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+
+ if (!fullname) {
+ fprintf(stderr, "qemu: could not find bios file '%s'\n",
+ bios_name);
+ exit(1);
+ }
+
+ memory_region_init_ram(rom, OBJECT(cpld), "rom",
+ 0x800000, &error_fatal);
+
+ memory_region_add_subregion(get_system_memory(),
+ 0xff800000, rom);
+
+ /* BIOS == image in rom (last 8MB of address space).
+ * Execution starts with the final word 0xfffffffc
+ */
+ int bsize = get_image_size(fullname);
+ if (bsize != 8 * 1024 * 1024 ||
+ -1 == load_image_targphys(fullname,
+ 0xff800000, 8 * 1024 * 1024))
+ {
+ fprintf(stderr, "qemu: could not load bios file '%s'"
+ " (%u bytes, requires 8MB)\n",
+ fullname, (unsigned)bsize);
+ exit(1);
+ }
+
+ memory_region_set_readonly(rom, true);
+
+ g_free(fullname);
+ }
+
+ {
+ hwaddr image_addr = mvme3100->load_address;
+
+ int image_size = load_image_targphys(machine->kernel_filename,
+ image_addr, 0x01000000);
+ if (machine->kernel_filename &&
+ -1 == image_size)
+ {
+ fprintf(stderr, "qemu: could not load file '%s'\n",
+ machine->kernel_filename);
+ exit(1);
+
+ } else if (mvme3100->entry_address == 0) {
+ mvme3100->entry_address = image_addr;
+
+ } else if (mvme3100->entry_address < image_addr
+ || mvme3100->entry_address >= image_addr + image_size)
+ {
+ fprintf(stderr, "qemu: entry-address out of range\n");
+ exit(1);
+ }
+
+ if (machine->kernel_cmdline) {
+ fw_cfg_add_i32(fwinfo, FW_CFG_CMDLINE_SIZE,
+ strlen(machine->kernel_cmdline) + 1);
+ fw_cfg_add_string(fwinfo, FW_CFG_CMDLINE_DATA,
+ machine->kernel_cmdline);
+ }
+
+ fw_cfg_add_i32(fwinfo, FW_CFG_KERNEL_ADDR, image_addr);
+ fw_cfg_add_i32(fwinfo, FW_CFG_KERNEL_ENTRY, mvme3100->entry_address);
+ fw_cfg_add_i32(fwinfo, FW_CFG_KERNEL_SIZE, image_size);
+ }
+}
+
+static void mvme3100_inst_init(Object *obj)
+{
+ MVME3100State *mvme3100 = MVME3100(obj);
+ mvme3100->load_address = 0x10000;
+ mvme3100->entry_address = 0;
+}
+
+static void mvme3100_visit_addr(Object *obj,
+ Visitor *v,
+ const char *name,
+ void *opaque,
+ Error **errp)
+{
+ MVME3100State *mvme3100 = MVME3100(obj);
+ uint32_t *ptr;
+
+ if (strcmp(name, "load-address") == 0) {
+ ptr = &mvme3100->load_address;
+ } else if (strcmp(name, "entry-address") == 0) {
+ ptr = &mvme3100->entry_address;
+ } else {
+ fprintf(stderr, "logic error: mvme3100 has no prop '%s'\n", name);
+ exit(1);
+ }
+
+ visit_type_uint32(v, name, ptr, errp);
+}
+
+static void ppce500_machine_class_init(ObjectClass *klass, void *raw)
+{
+ mvme3100_info *info = raw;
+ MachineClass *mc = MACHINE_CLASS(klass);
+ MVME3100Class *m3c = MVME3100_CLASS(klass);
+
+ m3c->info = info;
+
+ mc->desc = info->desc;
+ mc->init = mvme3100_init;
+ mc->max_cpus = 1;
+ mc->default_ram_size = info->ram_size;
+ mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("mpc8540_v21");
+
+ object_class_property_add(OBJECT_CLASS(mc), "load-address", "uint32",
+ &mvme3100_visit_addr, &mvme3100_visit_addr, NULL,
+ NULL, &error_fatal);
+ object_class_property_add(OBJECT_CLASS(mc), "entry-address", "uint32",
+ &mvme3100_visit_addr, &mvme3100_visit_addr, NULL,
+ NULL, &error_fatal);
+}
+
+static const TypeInfo mvme3100_type = {
+ .abstract = true,
+ .name = TYPE_MVME3100,
+ .parent = TYPE_MACHINE,
+ .instance_size = sizeof(MVME3100State),
+ .instance_init = mvme3100_inst_init,
+ .class_size = sizeof(MVME3100Class),
+};
+
+static mvme3100_info mvme3100_1152 = {
+ .desc = "MVME3100-1152",
+ .cpu_freq = 666666666u,
+ /* CCB/PCI -> 5/1
+ * core/CCB -> 2/1
+ *
+ * plat ratio = 5 -> 5:1 CCB:PCI
+ * e500 ratio = 4 -> 4:1 e500:CCB
+ */
+ .porpllsr = 0x0004000a,
+ .ram_size = 256 * (1 << 20),
+};
+
+static const TypeInfo mvme3100_1152_type = {
+ .name = MACHINE_TYPE_NAME("mvme3100-1152"),
+ .parent = TYPE_MVME3100,
+ .class_init = ppce500_machine_class_init,
+ .class_data = &mvme3100_1152,
+};
+
+static mvme3100_info mvme3100_1263 = {
+ .desc = "MVME3100-1263",
+ .cpu_freq = 833333333u,
+ /* CCB/PCI -> 5/1
+ * core/CCB -> 5/2
+ */
+ .porpllsr = 0x0005000a,
+ .ram_size = 512 * (1 << 20),
+};
+
+static const TypeInfo mvme3100_1263_type = {
+ .name = MACHINE_TYPE_NAME("mvme3100-1263"),
+ .parent = TYPE_MVME3100,
+ .class_init = ppce500_machine_class_init,
+ .class_data = &mvme3100_1263,
+};
+
+static void mvme3100_machine_init(void)
+{
+ type_register_static(&mvme3100_type);
+ type_register_static(&mvme3100_1152_type);
+ type_register_static(&mvme3100_1263_type);
+}
+
+type_init(mvme3100_machine_init)
diff --git a/hw/ppc/mvme3100_cpld.c b/hw/ppc/mvme3100_cpld.c
new file mode 100644
index 0000000000..41024566ce
--- /dev/null
+++ b/hw/ppc/mvme3100_cpld.c
@@ -0,0 +1,192 @@
+/*
+ * MVME3100 board CPLD (local logic)
+ *
+ * Copyright (c) 2015 Michael Davidsaver
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the LICENSE file in the top-level directory.
+ *
+ * This model was developed according to the
+ * MVME3100 Single Board Computer Programmer's Reference
+ * P/N: 6806800G37B
+ * July 2014
+ *
+ * And validated against the RTEMS 4.9.6 mvme3100 BSP
+ */
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "exec/address-spaces.h"
+#include "qemu-common.h"
+#include "sysemu/sysemu.h"
+#include "hw/sysbus.h"
+
+/* #define DEBUG_3100CPLD */
+
+#define TYPE_CPLD "mvme3100-cpld"
+
+#define CPLD(obj) OBJECT_CHECK(MVMECPLD, (obj), TYPE_CPLD)
+
+#ifdef DEBUG_3100CPLD
+#define DPRINTK(FMT, ...) printf(TYPE_CPLD " : " FMT, ## __VA_ARGS__)
+#else
+#define DPRINTK(FMT, ...) do {} while (0)
+#endif
+
+#define LOG(MSK, FMT, ...) qemu_log_mask(MSK, TYPE_CPLD " : " FMT, \
+ ## __VA_ARGS__)
+
+#define CPLD_SIZE 0x20
+
+typedef struct {
+ SysBusDevice parent_obj;
+
+ uint8_t mem[0x10];
+ uint32_t test;
+
+ MemoryRegion mmio;
+} MVMECPLD;
+
+static
+uint64_t cpld_read(void *opaque, hwaddr addr, unsigned size)
+{
+ MVMECPLD *self = opaque;
+ uint32_t offset = addr;
+ uint32_t val, A;
+
+ switch (offset) {
+ case 1 ... 0xf:
+ val = 0;
+ A = offset;
+ while (size--) {
+ val <<= 8;
+ val |= self->mem[A++];
+ }
+ break;
+ case 0x10:
+ val = self->test;
+ break;
+ case 0x14:
+ val = ~self->test;
+ break;
+ default:
+ LOG(LOG_UNIMP, "read from unimplimented register %08x\n",
+ (unsigned)offset);
+ val = 0;
+ }
+
+ DPRINTK("read %08x -> %08x\n", (unsigned)offset, (unsigned)val);
+
+ return val;
+}
+
+static
+void cpld_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
+{
+ MVMECPLD *self = opaque;
+ uint32_t offset = addr;
+
+ DPRINTK("write %08x <- %08x\n", (unsigned)offset, (unsigned)val);
+
+ switch (offset) {
+ case 0:
+ break;
+ case 1:
+ /* TODO: TSTAT_MASK and EEPROM_WPEEPROM */
+ if ((val & 0xe0) == 0xa0) {
+ qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
+ }
+ self->mem[offset >> 2] = val & 0x3;
+ break;
+ case 2:
+ self->mem[offset >> 2] = val & 0xf;
+ break;
+ case 3:
+ self->mem[offset >> 2] = val & 0x18;
+ break;
+ case 4 ... 9:
+ break;
+ case 10 ... 13:
+ /* TODO: allow date to be changed? */
+ break;
+ case 0x10:
+ self->test = val;
+ break;
+ case 0x11:
+ self->test = ~val;
+ break;
+ default:
+ LOG(LOG_UNIMP, "write to unimplimented register %08x\n",
+ (unsigned)offset);
+ break;
+ }
+}
+
+static const MemoryRegionOps cpld_ops = {
+ .read = cpld_read,
+ .write = cpld_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+static
+void mvme3100_cpld_realize(DeviceState *dev, Error **errp)
+{
+ MVMECPLD *self = CPLD(dev);
+
+ memory_region_init_io(&self->mmio, OBJECT(self), &cpld_ops, self,
+ TYPE_CPLD, CPLD_SIZE);
+
+ sysbus_init_mmio(&self->parent_obj, &self->mmio);
+}
+
+static Property mvme3100_cpld_props[] = {
+ DEFINE_PROP_END_OF_LIST()
+};
+
+static
+void mvme3100_cpld_reset(DeviceState *dev)
+{
+ MVMECPLD *self = CPLD(dev);
+
+ self->mem[0] = 0; /* Type VME SBC, SAFE_START==0 */
+ self->mem[1] = 3;
+ self->mem[2] = 1;
+ self->mem[3] = 9;
+ self->mem[4] = 9;
+ self->mem[5] = 0xa9;
+ self->mem[6] = 1;
+ self->mem[7] = 0xe0; /* TODO, TSEC phy irq status */
+ self->mem[8] = 1; /* TODO: PMC presence ...? */
+ self->mem[9] = 1; /* TODO: real rev. # */
+ self->mem[10] = 15; /* TODO: real date code */
+ self->mem[11] = 11;
+ self->mem[12] = 14;
+ self->mem[13] = 1;
+ self->test = 0;
+}
+
+static
+void mvme3100_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = &mvme3100_cpld_realize;
+ dc->reset = &mvme3100_cpld_reset;
+ dc->desc = "mvme3100 CPLD logic";
+ dc->props = mvme3100_cpld_props;
+}
+
+static const TypeInfo mvme3100_cpld_info = {
+ .name = TYPE_CPLD,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(MVMECPLD),
+ .class_size = sizeof(SysBusDeviceClass),
+ .class_init = mvme3100_class_init,
+};
+
+static
+void mvme3100_cpld_register(void)
+{
+ type_register_static(&mvme3100_cpld_info);
+}
+
+type_init(mvme3100_cpld_register)
--
2.11.0
next prev parent reply other threads:[~2017-11-20 3:25 UTC|newest]
Thread overview: 33+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-11-20 3:24 [Qemu-devel] [PATCH 00/12] Add MVME3100 PPC SBC Michael Davidsaver
2017-11-20 3:24 ` [Qemu-devel] [PATCH 01/12] e500: add board config options Michael Davidsaver
2017-11-22 3:28 ` David Gibson
2017-11-22 17:55 ` Michael Davidsaver
2017-11-23 16:07 ` [Qemu-devel] [Qemu-ppc] " Cédric Le Goater
2017-11-24 0:21 ` [Qemu-devel] " David Gibson
2017-11-20 3:24 ` [Qemu-devel] [PATCH 03/12] e500: note possible bug with host bridge Michael Davidsaver
2017-11-22 3:46 ` David Gibson
2017-11-22 4:57 ` Michael Davidsaver
2017-11-20 3:24 ` [Qemu-devel] [PATCH 04/12] e500: additional CCSR registers Michael Davidsaver
2017-11-22 3:57 ` David Gibson
2017-11-20 3:24 ` [Qemu-devel] [PATCH 05/12] e500: name openpic and pci host bridge Michael Davidsaver
2017-11-22 3:58 ` David Gibson
2017-11-20 3:24 ` [Qemu-devel] [PATCH 06/12] i2c: add mpc8540 i2c controller Michael Davidsaver
2017-11-22 4:06 ` David Gibson
2017-11-23 15:39 ` [Qemu-devel] [Qemu-ppc] " Cédric Le Goater
2017-11-24 0:13 ` David Gibson
2017-11-20 3:24 ` [Qemu-devel] [PATCH 07/12] qtest: add e500_i2c_create() Michael Davidsaver
2017-11-20 3:24 ` [Qemu-devel] [PATCH 08/12] e500: add mpc8540 i2c controller to ccsr Michael Davidsaver
2017-11-22 4:08 ` David Gibson
2017-11-22 16:46 ` Michael Davidsaver
2017-11-20 3:24 ` [Qemu-devel] [PATCH 09/12] nvram: add AT24Cx i2c eeprom Michael Davidsaver
2017-11-22 4:10 ` David Gibson
2017-11-20 3:24 ` [Qemu-devel] [PATCH 10/12] timer: add ds1375 RTC Michael Davidsaver
2017-11-22 4:11 ` David Gibson
2017-11-20 3:24 ` Michael Davidsaver [this message]
2017-11-20 3:24 ` [Qemu-devel] [PATCH 12/12] tests: add mvme3100-test Michael Davidsaver
[not found] ` <20171120032420.9134-3-mdavidsaver@gmail.com>
2017-11-22 3:36 ` [Qemu-devel] [PATCH 02/12] e500: consolidate mpc8540 guts with e500-ccsr David Gibson
2017-12-06 3:12 ` David Gibson
2017-12-06 3:18 ` Michael Davidsaver
2017-12-06 4:23 ` David Gibson
2017-11-22 4:12 ` [Qemu-devel] [PATCH 00/12] Add MVME3100 PPC SBC David Gibson
2017-11-22 4:58 ` Michael Davidsaver
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20171120032420.9134-12-mdavidsaver@gmail.com \
--to=mdavidsaver@gmail.com \
--cc=agraf@suse.de \
--cc=david@gibson.dropbear.id.au \
--cc=qemu-devel@nongnu.org \
--cc=qemu-ppc@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.