summary refs log tree commit diff stats
path: root/hw
diff options
context:
space:
mode:
authorBlue Swirl <blauwirbel@gmail.com>2011-07-01 21:12:50 +0000
committerBlue Swirl <blauwirbel@gmail.com>2011-07-01 21:12:50 +0000
commit3b88670664f7902000b83149e7fa1875ad5c6239 (patch)
tree680e0ef80f570aed7e6c0686d7c7c7786364aa93 /hw
parentec1884298c96a8ce723880adb9e8ffe5e71fcf37 (diff)
parent1c53accceeb01246aea0ec361e1efd15cac6db0f (diff)
downloadfocaccia-qemu-3b88670664f7902000b83149e7fa1875ad5c6239.tar.gz
focaccia-qemu-3b88670664f7902000b83149e7fa1875ad5c6239.zip
Merge branch 'ppc-next' of git://repo.or.cz/qemu/agraf
* 'ppc-next' of git://repo.or.cz/qemu/agraf:
  PPC: move TLBs to their own arrays
  PPC: 440: Use 440 style MMU as default, so Qemu knows the MMU type
  PPC: E500: Use MAS registers instead of internal TLB representation
  PPC: Only set lower 32bits with mtmsr
  PPC: update openbios firmware
  PPC: mpc8544ds: Add hypervisor node
  PPC: calculate kernel,initrd,cmdline locations dynamically
  target-ppc: Handle memory-forced I/O controller access
  PPC: E500: Implement reboot controller
Diffstat (limited to 'hw')
-rw-r--r--hw/mpc8544_guts.c135
-rw-r--r--hw/ppc440.c5
-rw-r--r--hw/ppc_mac.h3
-rw-r--r--hw/ppc_newworld.c15
-rw-r--r--hw/ppc_oldworld.c15
-rw-r--r--hw/ppce500_mpc8544ds.c46
-rw-r--r--hw/virtex_ml507.c4
7 files changed, 195 insertions, 28 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);
diff --git a/hw/ppc440.c b/hw/ppc440.c
index 1ed001a031..90abc91929 100644
--- a/hw/ppc440.c
+++ b/hw/ppc440.c
@@ -45,8 +45,9 @@ CPUState *ppc440ep_init(ram_addr_t *ram_size, PCIBus **pcip,
     qemu_irq *irqs;
     qemu_irq *pci_irqs;
 
-    if (cpu_model == NULL)
-        cpu_model = "405"; // XXX: should be 440EP
+    if (cpu_model == NULL) {
+        cpu_model = "440-Xilinx"; // XXX: should be 440EP
+    }
     env = cpu_init(cpu_model);
     if (!env) {
         fprintf(stderr, "Unable to initialize CPU!\n");
diff --git a/hw/ppc_mac.h b/hw/ppc_mac.h
index ea8759324c..68dade7e40 100644
--- a/hw/ppc_mac.h
+++ b/hw/ppc_mac.h
@@ -35,8 +35,7 @@
 #define PROM_ADDR         0xfff00000
 
 #define KERNEL_LOAD_ADDR 0x01000000
-#define CMDLINE_ADDR     0x027ff000
-#define INITRD_LOAD_ADDR 0x02800000
+#define KERNEL_GAP       0x00100000
 
 #define ESCC_CLOCK 3686400
 
diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c
index 86f1cfbee9..5bce709bab 100644
--- a/hw/ppc_newworld.c
+++ b/hw/ppc_newworld.c
@@ -120,6 +120,11 @@ static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
     return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR;
 }
 
+static target_phys_addr_t round_page(target_phys_addr_t addr)
+{
+    return (addr + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
+}
+
 /* PowerPC Mac99 hardware initialisation */
 static void ppc_core99_init (ram_addr_t ram_size,
                              const char *boot_device,
@@ -134,7 +139,7 @@ static void ppc_core99_init (ram_addr_t ram_size,
     int unin_memory;
     int linux_boot, i;
     ram_addr_t ram_offset, bios_offset;
-    uint32_t kernel_base, initrd_base;
+    target_phys_addr_t kernel_base, initrd_base, cmdline_base = 0;
     long kernel_size, initrd_size;
     PCIBus *pci_bus;
     MacIONVRAMState *nvr;
@@ -220,7 +225,7 @@ static void ppc_core99_init (ram_addr_t ram_size,
         }
         /* load initrd */
         if (initrd_filename) {
-            initrd_base = INITRD_LOAD_ADDR;
+            initrd_base = round_page(kernel_base + kernel_size + KERNEL_GAP);
             initrd_size = load_image_targphys(initrd_filename, initrd_base,
                                               ram_size - initrd_base);
             if (initrd_size < 0) {
@@ -228,9 +233,11 @@ static void ppc_core99_init (ram_addr_t ram_size,
                          initrd_filename);
                 exit(1);
             }
+            cmdline_base = round_page(initrd_base + initrd_size);
         } else {
             initrd_base = 0;
             initrd_size = 0;
+            cmdline_base = round_page(kernel_base + kernel_size + KERNEL_GAP);
         }
         ppc_boot_device = 'm';
     } else {
@@ -373,8 +380,8 @@ static void ppc_core99_init (ram_addr_t ram_size,
     fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, kernel_base);
     fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
     if (kernel_cmdline) {
-        fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, CMDLINE_ADDR);
-        pstrcpy_targphys("cmdline", CMDLINE_ADDR, TARGET_PAGE_SIZE, kernel_cmdline);
+        fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, cmdline_base);
+        pstrcpy_targphys("cmdline", cmdline_base, TARGET_PAGE_SIZE, kernel_cmdline);
     } else {
         fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0);
     }
diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c
index 75a312742e..20cd8e1a8d 100644
--- a/hw/ppc_oldworld.c
+++ b/hw/ppc_oldworld.c
@@ -59,6 +59,11 @@ static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
     return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR;
 }
 
+static target_phys_addr_t round_page(target_phys_addr_t addr)
+{
+    return (addr + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
+}
+
 static void ppc_heathrow_init (ram_addr_t ram_size,
                                const char *boot_device,
                                const char *kernel_filename,
@@ -71,7 +76,7 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
     qemu_irq *pic, **heathrow_irqs;
     int linux_boot, i;
     ram_addr_t ram_offset, bios_offset;
-    uint32_t kernel_base, initrd_base;
+    uint32_t kernel_base, initrd_base, cmdline_base = 0;
     int32_t kernel_size, initrd_size;
     PCIBus *pci_bus;
     MacIONVRAMState *nvr;
@@ -157,7 +162,7 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
         }
         /* load initrd */
         if (initrd_filename) {
-            initrd_base = INITRD_LOAD_ADDR;
+            initrd_base = round_page(kernel_base + kernel_size + KERNEL_GAP);
             initrd_size = load_image_targphys(initrd_filename, initrd_base,
                                               ram_size - initrd_base);
             if (initrd_size < 0) {
@@ -165,9 +170,11 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
                          initrd_filename);
                 exit(1);
             }
+            cmdline_base = round_page(initrd_base + initrd_size);
         } else {
             initrd_base = 0;
             initrd_size = 0;
+            cmdline_base = round_page(kernel_base + kernel_size + KERNEL_GAP);
         }
         ppc_boot_device = 'm';
     } else {
@@ -278,8 +285,8 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
     fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, kernel_base);
     fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
     if (kernel_cmdline) {
-        fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, CMDLINE_ADDR);
-        pstrcpy_targphys("cmdline", CMDLINE_ADDR, TARGET_PAGE_SIZE, kernel_cmdline);
+        fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, cmdline_base);
+        pstrcpy_targphys("cmdline", cmdline_base, TARGET_PAGE_SIZE, kernel_cmdline);
     } else {
         fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_CMDLINE, 0);
     }
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index 6b57fbf597..b739ce27ed 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -50,6 +50,7 @@
 #define MPC8544_PCI_REGS_SIZE      0x1000
 #define MPC8544_PCI_IO             0xE1000000
 #define MPC8544_PCI_IOLEN          0x10000
+#define MPC8544_UTIL_BASE          (MPC8544_CCSRBAR_BASE + 0xe0000)
 
 struct boot_info
 {
@@ -81,11 +82,12 @@ out:
 }
 #endif
 
-static int mpc8544_load_device_tree(target_phys_addr_t addr,
-                                     uint32_t ramsize,
-                                     target_phys_addr_t initrd_base,
-                                     target_phys_addr_t initrd_size,
-                                     const char *kernel_cmdline)
+static int mpc8544_load_device_tree(CPUState *env,
+                                    target_phys_addr_t addr,
+                                    uint32_t ramsize,
+                                    target_phys_addr_t initrd_base,
+                                    target_phys_addr_t initrd_size,
+                                    const char *kernel_cmdline)
 {
     int ret = -1;
 #ifdef CONFIG_FDT
@@ -93,6 +95,7 @@ static int mpc8544_load_device_tree(target_phys_addr_t addr,
     char *filename;
     int fdt_size;
     void *fdt;
+    uint8_t hypercall[16];
 
     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
     if (!filename) {
@@ -156,6 +159,13 @@ static int mpc8544_load_device_tree(target_phys_addr_t addr,
 
         mpc8544_copy_soc_cell(fdt, buf, "clock-frequency");
         mpc8544_copy_soc_cell(fdt, buf, "timebase-frequency");
+
+        /* indicate KVM hypercall interface */
+        qemu_devtree_setprop_string(fdt, "/hypervisor", "compatible",
+                                    "linux,kvm");
+        kvmppc_get_hypercall(env, hypercall, sizeof(hypercall));
+        qemu_devtree_setprop(fdt, "/hypervisor", "hcall-instructions",
+                             hypercall, sizeof(hypercall));
     } else {
         const uint32_t freq = 400000000;
 
@@ -175,18 +185,23 @@ out:
 }
 
 /* Create -kernel TLB entries for BookE, linearly spanning 256MB.  */
+static inline target_phys_addr_t booke206_page_size_to_tlb(uint64_t size)
+{
+    return (ffs(size >> 10) - 1) >> 1;
+}
+
 static void mmubooke_create_initial_mapping(CPUState *env,
                                      target_ulong va,
                                      target_phys_addr_t pa)
 {
-    ppcemb_tlb_t *tlb = booke206_get_tlbe(env, 1, 0, 0);
-
-    tlb->attr = 0;
-    tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
-    tlb->size = 256 * 1024 * 1024;
-    tlb->EPN = va & TARGET_PAGE_MASK;
-    tlb->RPN = pa & TARGET_PAGE_MASK;
-    tlb->PID = 0;
+    ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0);
+    target_phys_addr_t size;
+
+    size = (booke206_page_size_to_tlb(256 * 1024 * 1024) << MAS1_TSIZE_SHIFT);
+    tlb->mas1 = MAS1_VALID | size;
+    tlb->mas2 = va & TARGET_PAGE_MASK;
+    tlb->mas7_3 = pa & TARGET_PAGE_MASK;
+    tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
 }
 
 static void mpc8544ds_cpu_reset(void *opaque)
@@ -270,6 +285,9 @@ static void mpc8544ds_init(ram_addr_t ram_size,
                        serial_hds[0], 1, 1);
     }
 
+    /* General Utility device */
+    sysbus_create_simple("mpc8544-guts", MPC8544_UTIL_BASE, NULL);
+
     /* PCI */
     dev = sysbus_create_varargs("e500-pcihost", MPC8544_PCI_REGS_BASE,
                                 mpic[pci_irq_nrs[0]], mpic[pci_irq_nrs[1]],
@@ -326,7 +344,7 @@ static void mpc8544ds_init(ram_addr_t ram_size,
         cpu_abort(env, "Compiled without FDT support - can't load kernel\n");
 #endif
         dt_base = (kernel_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
-        if (mpc8544_load_device_tree(dt_base, ram_size,
+        if (mpc8544_load_device_tree(env, dt_base, ram_size,
                     initrd_base, initrd_size, kernel_cmdline) < 0) {
             fprintf(stderr, "couldn't load device tree\n");
             exit(1);
diff --git a/hw/virtex_ml507.c b/hw/virtex_ml507.c
index fa605158e7..7bde8c79de 100644
--- a/hw/virtex_ml507.c
+++ b/hw/virtex_ml507.c
@@ -60,7 +60,7 @@ static void mmubooke_create_initial_mapping(CPUState *env,
                                      target_ulong va,
                                      target_phys_addr_t pa)
 {
-    ppcemb_tlb_t *tlb = &env->tlb[0].tlbe;
+    ppcemb_tlb_t *tlb = &env->tlb.tlbe[0];
 
     tlb->attr = 0;
     tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
@@ -69,7 +69,7 @@ static void mmubooke_create_initial_mapping(CPUState *env,
     tlb->RPN = pa & TARGET_PAGE_MASK;
     tlb->PID = 0;
 
-    tlb = &env->tlb[1].tlbe;
+    tlb = &env->tlb.tlbe[1];
     tlb->attr = 0;
     tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
     tlb->size = 1 << 31; /* up to 0xffffffff  */