summaryrefslogtreecommitdiff
path: root/hw/mpc8544_guts.c
diff options
context:
space:
mode:
authorAlexander Graf <agraf@suse.de>2011-06-02 13:53:40 +0200
committerAlexander Graf <agraf@suse.de>2011-06-17 02:58:23 +0200
commitb0fb84236da4a36a852010b6b5d5d3ca497a2b68 (patch)
tree870571337a99ee5de81c8150a641b49f80a27bd0 /hw/mpc8544_guts.c
parenteb47d7c5d96060040931c42773ee07e61e547af9 (diff)
downloadqemu-b0fb84236da4a36a852010b6b5d5d3ca497a2b68.tar.gz
qemu-b0fb84236da4a36a852010b6b5d5d3ca497a2b68.tar.bz2
qemu-b0fb84236da4a36a852010b6b5d5d3ca497a2b68.zip
PPC: E500: Implement reboot controller
When Linux reboots an e500 VM, it writes to a magic register in the "global-utilities" device indicated by the device tree. We were not emulating that device so far, rendering the VM reboot-less. This patch implements that device with only the reboot functionality implemented and adds it to the device tree. With this patch applied, I can successfully reboot a -M mpc8544ds VM. Signed-off-by: Alexander Graf <agraf@suse.de> Reviewed-by: Andreas Färber <andreas.faerber@web.de>
Diffstat (limited to 'hw/mpc8544_guts.c')
-rw-r--r--hw/mpc8544_guts.c135
1 files changed, 135 insertions, 0 deletions
diff --git a/hw/mpc8544_guts.c b/hw/mpc8544_guts.c
new file mode 100644
index 0000000000..c685f3e08c
--- /dev/null
+++ b/hw/mpc8544_guts.c
@@ -0,0 +1,135 @@
+/*
+ * QEMU PowerPC MPC8544 global util pseudo-device
+ *
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Author: Alexander Graf, <alex@csgraf.de>
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * *****************************************************************
+ *
+ * The documentation for this device is noted in the MPC8544 documentation,
+ * file name "MPC8544ERM.pdf". You can easily find it on the web.
+ *
+ */
+
+#include "hw.h"
+#include "sysemu.h"
+#include "sysbus.h"
+
+#define MPC8544_GUTS_MMIO_SIZE 0x1000
+#define MPC8544_GUTS_RSTCR_RESET 0x02
+
+#define MPC8544_GUTS_ADDR_PORPLLSR 0x00
+#define MPC8544_GUTS_ADDR_PORBMSR 0x04
+#define MPC8544_GUTS_ADDR_PORIMPSCR 0x08
+#define MPC8544_GUTS_ADDR_PORDEVSR 0x0C
+#define MPC8544_GUTS_ADDR_PORDBGMSR 0x10
+#define MPC8544_GUTS_ADDR_PORDEVSR2 0x14
+#define MPC8544_GUTS_ADDR_GPPORCR 0x20
+#define MPC8544_GUTS_ADDR_GPIOCR 0x30
+#define MPC8544_GUTS_ADDR_GPOUTDR 0x40
+#define MPC8544_GUTS_ADDR_GPINDR 0x50
+#define MPC8544_GUTS_ADDR_PMUXCR 0x60
+#define MPC8544_GUTS_ADDR_DEVDISR 0x70
+#define MPC8544_GUTS_ADDR_POWMGTCSR 0x80
+#define MPC8544_GUTS_ADDR_MCPSUMR 0x90
+#define MPC8544_GUTS_ADDR_RSTRSCR 0x94
+#define MPC8544_GUTS_ADDR_PVR 0xA0
+#define MPC8544_GUTS_ADDR_SVR 0xA4
+#define MPC8544_GUTS_ADDR_RSTCR 0xB0
+#define MPC8544_GUTS_ADDR_IOVSELSR 0xC0
+#define MPC8544_GUTS_ADDR_DDRCSR 0xB20
+#define MPC8544_GUTS_ADDR_DDRCDR 0xB24
+#define MPC8544_GUTS_ADDR_DDRCLKDR 0xB28
+#define MPC8544_GUTS_ADDR_CLKOCR 0xE00
+#define MPC8544_GUTS_ADDR_SRDS1CR1 0xF04
+#define MPC8544_GUTS_ADDR_SRDS2CR1 0xF10
+#define MPC8544_GUTS_ADDR_SRDS2CR3 0xF18
+
+struct GutsState {
+ SysBusDevice busdev;
+};
+
+typedef struct GutsState GutsState;
+
+static uint32_t mpc8544_guts_read32(void *opaque, target_phys_addr_t addr)
+{
+ uint32_t value = 0;
+ CPUState *env = cpu_single_env;
+
+ addr &= MPC8544_GUTS_MMIO_SIZE - 1;
+ switch (addr) {
+ case MPC8544_GUTS_ADDR_PVR:
+ value = env->spr[SPR_PVR];
+ break;
+ case MPC8544_GUTS_ADDR_SVR:
+ value = env->spr[SPR_E500_SVR];
+ break;
+ default:
+ fprintf(stderr, "guts: Unknown register read: %x\n", (int)addr);
+ break;
+ }
+
+ return value;
+}
+
+static CPUReadMemoryFunc * const mpc8544_guts_read[] = {
+ NULL,
+ NULL,
+ &mpc8544_guts_read32,
+};
+
+static void mpc8544_guts_write32(void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+ addr &= MPC8544_GUTS_MMIO_SIZE - 1;
+
+ switch (addr) {
+ case MPC8544_GUTS_ADDR_RSTCR:
+ if (value & MPC8544_GUTS_RSTCR_RESET) {
+ qemu_system_reset_request();
+ }
+ break;
+ default:
+ fprintf(stderr, "guts: Unknown register write: %x = %x\n",
+ (int)addr, value);
+ break;
+ }
+}
+
+static CPUWriteMemoryFunc * const mpc8544_guts_write[] = {
+ NULL,
+ NULL,
+ &mpc8544_guts_write32,
+};
+
+static int mpc8544_guts_initfn(SysBusDevice *dev)
+{
+ GutsState *s;
+ int iomem;
+
+ s = FROM_SYSBUS(GutsState, sysbus_from_qdev(dev));
+
+ iomem = cpu_register_io_memory(mpc8544_guts_read, mpc8544_guts_write, s,
+ DEVICE_BIG_ENDIAN);
+ sysbus_init_mmio(dev, MPC8544_GUTS_MMIO_SIZE, iomem);
+
+ return 0;
+}
+
+static SysBusDeviceInfo mpc8544_guts_info = {
+ .init = mpc8544_guts_initfn,
+ .qdev.name = "mpc8544-guts",
+ .qdev.size = sizeof(GutsState),
+};
+
+static void mpc8544_guts_register(void)
+{
+ sysbus_register_withprop(&mpc8544_guts_info);
+}
+device_init(mpc8544_guts_register);