aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 1 | /* |
Stefan Weil | 5cbdb3a | 2012-04-07 09:23:39 +0200 | [diff] [blame] | 2 | * QEMU PowerPC MPC8544DS board emulation |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 3 | * |
| 4 | * Copyright (C) 2009 Freescale Semiconductor, Inc. All rights reserved. |
| 5 | * |
| 6 | * Author: Yu Liu, <yu.liu@freescale.com> |
| 7 | * |
| 8 | * This file is derived from hw/ppc440_bamboo.c, |
| 9 | * the copyright for that material belongs to the original owners. |
| 10 | * |
| 11 | * This is free software; you can redistribute it and/or modify |
| 12 | * it under the terms of the GNU General Public License as published by |
| 13 | * the Free Software Foundation; either version 2 of the License, or |
| 14 | * (at your option) any later version. |
| 15 | */ |
| 16 | |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 17 | #include "config.h" |
| 18 | #include "qemu-common.h" |
| 19 | #include "net.h" |
| 20 | #include "hw.h" |
| 21 | #include "pc.h" |
| 22 | #include "pci.h" |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 23 | #include "boards.h" |
| 24 | #include "sysemu.h" |
| 25 | #include "kvm.h" |
| 26 | #include "kvm_ppc.h" |
| 27 | #include "device_tree.h" |
| 28 | #include "openpic.h" |
Alexander Graf | 3b989d4 | 2011-04-30 23:34:53 +0200 | [diff] [blame] | 29 | #include "ppc.h" |
Blue Swirl | ca20cf3 | 2009-09-20 14:58:02 +0000 | [diff] [blame] | 30 | #include "loader.h" |
| 31 | #include "elf.h" |
Alexander Graf | be13cc7 | 2010-08-31 00:22:28 +0200 | [diff] [blame] | 32 | #include "sysbus.h" |
Richard Henderson | 39186d8 | 2011-08-11 16:07:16 -0700 | [diff] [blame] | 33 | #include "exec-memory.h" |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 34 | |
| 35 | #define BINARY_DEVICE_TREE_FILE "mpc8544ds.dtb" |
| 36 | #define UIMAGE_LOAD_BASE 0 |
Liu Yu | 75bb658 | 2010-02-02 16:49:03 +0800 | [diff] [blame] | 37 | #define DTC_LOAD_PAD 0x500000 |
| 38 | #define DTC_PAD_MASK 0xFFFFF |
| 39 | #define INITRD_LOAD_PAD 0x2000000 |
| 40 | #define INITRD_PAD_MASK 0xFFFFFF |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 41 | |
| 42 | #define RAM_SIZES_ALIGN (64UL << 20) |
| 43 | |
| 44 | #define MPC8544_CCSRBAR_BASE 0xE0000000 |
| 45 | #define MPC8544_MPIC_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x40000) |
| 46 | #define MPC8544_SERIAL0_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x4500) |
| 47 | #define MPC8544_SERIAL1_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x4600) |
| 48 | #define MPC8544_PCI_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x8000) |
| 49 | #define MPC8544_PCI_REGS_SIZE 0x1000 |
| 50 | #define MPC8544_PCI_IO 0xE1000000 |
| 51 | #define MPC8544_PCI_IOLEN 0x10000 |
Alexander Graf | b0fb842 | 2011-06-02 13:53:40 +0200 | [diff] [blame] | 52 | #define MPC8544_UTIL_BASE (MPC8544_CCSRBAR_BASE + 0xe0000) |
Alexander Graf | 5c145da | 2011-07-22 13:32:29 +0200 | [diff] [blame] | 53 | #define MPC8544_SPIN_BASE 0xEF000000 |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 54 | |
Alexander Graf | 3b989d4 | 2011-04-30 23:34:53 +0200 | [diff] [blame] | 55 | struct boot_info |
| 56 | { |
| 57 | uint32_t dt_base; |
| 58 | uint32_t entry; |
| 59 | }; |
| 60 | |
Andreas Färber | e2684c0 | 2012-03-14 01:38:23 +0100 | [diff] [blame] | 61 | static int mpc8544_load_device_tree(CPUPPCState *env, |
Alexander Graf | 5de6b46 | 2011-06-15 23:34:04 +0200 | [diff] [blame] | 62 | target_phys_addr_t addr, |
| 63 | uint32_t ramsize, |
| 64 | target_phys_addr_t initrd_base, |
| 65 | target_phys_addr_t initrd_size, |
| 66 | const char *kernel_cmdline) |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 67 | { |
Aurelien Jarno | dbf916d | 2010-02-27 19:47:22 +0100 | [diff] [blame] | 68 | int ret = -1; |
Juan Quintela | 3f0855b | 2009-07-27 16:12:52 +0200 | [diff] [blame] | 69 | #ifdef CONFIG_FDT |
Alexander Graf | 3b989d4 | 2011-04-30 23:34:53 +0200 | [diff] [blame] | 70 | uint32_t mem_reg_property[] = {0, cpu_to_be32(ramsize)}; |
Paul Brook | 5cea859 | 2009-05-30 00:52:44 +0100 | [diff] [blame] | 71 | char *filename; |
pbrook | 7ec632b | 2009-04-10 16:23:59 +0000 | [diff] [blame] | 72 | int fdt_size; |
Aurelien Jarno | dbf916d | 2010-02-27 19:47:22 +0100 | [diff] [blame] | 73 | void *fdt; |
Alexander Graf | 5de6b46 | 2011-06-15 23:34:04 +0200 | [diff] [blame] | 74 | uint8_t hypercall[16]; |
Alexander Graf | 911d6e7 | 2011-07-21 02:34:11 +0200 | [diff] [blame] | 75 | uint32_t clock_freq = 400000000; |
| 76 | uint32_t tb_freq = 400000000; |
Alexander Graf | 621d05e | 2011-07-21 03:01:11 +0200 | [diff] [blame] | 77 | int i; |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 78 | |
Paul Brook | 5cea859 | 2009-05-30 00:52:44 +0100 | [diff] [blame] | 79 | filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE); |
| 80 | if (!filename) { |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 81 | goto out; |
Paul Brook | 5cea859 | 2009-05-30 00:52:44 +0100 | [diff] [blame] | 82 | } |
| 83 | fdt = load_device_tree(filename, &fdt_size); |
Anthony Liguori | 7267c09 | 2011-08-20 22:09:37 -0500 | [diff] [blame] | 84 | g_free(filename); |
Paul Brook | 5cea859 | 2009-05-30 00:52:44 +0100 | [diff] [blame] | 85 | if (fdt == NULL) { |
| 86 | goto out; |
| 87 | } |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 88 | |
| 89 | /* Manipulate device tree in memory. */ |
| 90 | ret = qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property, |
| 91 | sizeof(mem_reg_property)); |
| 92 | if (ret < 0) |
| 93 | fprintf(stderr, "couldn't set /memory/reg\n"); |
| 94 | |
Alexander Graf | 3b989d4 | 2011-04-30 23:34:53 +0200 | [diff] [blame] | 95 | if (initrd_size) { |
| 96 | ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start", |
| 97 | initrd_base); |
| 98 | if (ret < 0) { |
| 99 | fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n"); |
| 100 | } |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 101 | |
Alexander Graf | 3b989d4 | 2011-04-30 23:34:53 +0200 | [diff] [blame] | 102 | ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end", |
| 103 | (initrd_base + initrd_size)); |
| 104 | if (ret < 0) { |
| 105 | fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n"); |
| 106 | } |
| 107 | } |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 108 | |
| 109 | ret = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", |
| 110 | kernel_cmdline); |
| 111 | if (ret < 0) |
| 112 | fprintf(stderr, "couldn't set /chosen/bootargs\n"); |
| 113 | |
| 114 | if (kvm_enabled()) { |
Alexander Graf | 911d6e7 | 2011-07-21 02:34:11 +0200 | [diff] [blame] | 115 | /* Read out host's frequencies */ |
| 116 | clock_freq = kvmppc_get_clockfreq(); |
| 117 | tb_freq = kvmppc_get_tbfreq(); |
Alexander Graf | 5de6b46 | 2011-06-15 23:34:04 +0200 | [diff] [blame] | 118 | |
| 119 | /* indicate KVM hypercall interface */ |
| 120 | qemu_devtree_setprop_string(fdt, "/hypervisor", "compatible", |
| 121 | "linux,kvm"); |
| 122 | kvmppc_get_hypercall(env, hypercall, sizeof(hypercall)); |
| 123 | qemu_devtree_setprop(fdt, "/hypervisor", "hcall-instructions", |
| 124 | hypercall, sizeof(hypercall)); |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 125 | } |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 126 | |
Alexander Graf | 1e3debf | 2011-07-23 10:56:40 +0200 | [diff] [blame] | 127 | /* We need to generate the cpu nodes in reverse order, so Linux can pick |
| 128 | the first node as boot node and be happy */ |
| 129 | for (i = smp_cpus - 1; i >= 0; i--) { |
Alexander Graf | 621d05e | 2011-07-21 03:01:11 +0200 | [diff] [blame] | 130 | char cpu_name[128]; |
Alexander Graf | 1e3debf | 2011-07-23 10:56:40 +0200 | [diff] [blame] | 131 | uint64_t cpu_release_addr = cpu_to_be64(MPC8544_SPIN_BASE + (i * 0x20)); |
Alexander Graf | 10f25a4 | 2011-07-21 03:06:12 +0200 | [diff] [blame] | 132 | |
Alexander Graf | 1e3debf | 2011-07-23 10:56:40 +0200 | [diff] [blame] | 133 | for (env = first_cpu; env != NULL; env = env->next_cpu) { |
| 134 | if (env->cpu_index == i) { |
| 135 | break; |
| 136 | } |
| 137 | } |
| 138 | |
| 139 | if (!env) { |
| 140 | continue; |
| 141 | } |
| 142 | |
| 143 | snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x", env->cpu_index); |
| 144 | qemu_devtree_add_subnode(fdt, cpu_name); |
Alexander Graf | 621d05e | 2011-07-21 03:01:11 +0200 | [diff] [blame] | 145 | qemu_devtree_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq); |
| 146 | qemu_devtree_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq); |
Alexander Graf | 1e3debf | 2011-07-23 10:56:40 +0200 | [diff] [blame] | 147 | qemu_devtree_setprop_string(fdt, cpu_name, "device_type", "cpu"); |
| 148 | qemu_devtree_setprop_cell(fdt, cpu_name, "reg", env->cpu_index); |
| 149 | qemu_devtree_setprop_cell(fdt, cpu_name, "d-cache-line-size", |
| 150 | env->dcache_line_size); |
| 151 | qemu_devtree_setprop_cell(fdt, cpu_name, "i-cache-line-size", |
| 152 | env->icache_line_size); |
| 153 | qemu_devtree_setprop_cell(fdt, cpu_name, "d-cache-size", 0x8000); |
| 154 | qemu_devtree_setprop_cell(fdt, cpu_name, "i-cache-size", 0x8000); |
| 155 | qemu_devtree_setprop_cell(fdt, cpu_name, "bus-frequency", 0); |
| 156 | if (env->cpu_index) { |
| 157 | qemu_devtree_setprop_string(fdt, cpu_name, "status", "disabled"); |
| 158 | qemu_devtree_setprop_string(fdt, cpu_name, "enable-method", "spin-table"); |
| 159 | qemu_devtree_setprop(fdt, cpu_name, "cpu-release-addr", |
| 160 | &cpu_release_addr, sizeof(cpu_release_addr)); |
| 161 | } else { |
| 162 | qemu_devtree_setprop_string(fdt, cpu_name, "status", "okay"); |
| 163 | } |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 164 | } |
| 165 | |
Liu Yu | 04088ad | 2010-02-02 16:49:02 +0800 | [diff] [blame] | 166 | ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr); |
Anthony Liguori | 7267c09 | 2011-08-20 22:09:37 -0500 | [diff] [blame] | 167 | g_free(fdt); |
pbrook | 7ec632b | 2009-04-10 16:23:59 +0000 | [diff] [blame] | 168 | |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 169 | out: |
| 170 | #endif |
| 171 | |
Liu Yu | 04088ad | 2010-02-02 16:49:02 +0800 | [diff] [blame] | 172 | return ret; |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 173 | } |
| 174 | |
Alexander Graf | 3b989d4 | 2011-04-30 23:34:53 +0200 | [diff] [blame] | 175 | /* Create -kernel TLB entries for BookE, linearly spanning 256MB. */ |
Alexander Graf | d1e256f | 2011-06-16 18:45:43 +0200 | [diff] [blame] | 176 | static inline target_phys_addr_t booke206_page_size_to_tlb(uint64_t size) |
| 177 | { |
Scott Wood | 2bd9543 | 2011-08-18 10:38:40 +0000 | [diff] [blame] | 178 | return ffs(size >> 10) - 1; |
Alexander Graf | d1e256f | 2011-06-16 18:45:43 +0200 | [diff] [blame] | 179 | } |
| 180 | |
Andreas Färber | e2684c0 | 2012-03-14 01:38:23 +0100 | [diff] [blame] | 181 | static void mmubooke_create_initial_mapping(CPUPPCState *env, |
Alexander Graf | 3b989d4 | 2011-04-30 23:34:53 +0200 | [diff] [blame] | 182 | target_ulong va, |
| 183 | target_phys_addr_t pa) |
| 184 | { |
Alexander Graf | d1e256f | 2011-06-16 18:45:43 +0200 | [diff] [blame] | 185 | ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0); |
| 186 | target_phys_addr_t size; |
Alexander Graf | 3b989d4 | 2011-04-30 23:34:53 +0200 | [diff] [blame] | 187 | |
Alexander Graf | d1e256f | 2011-06-16 18:45:43 +0200 | [diff] [blame] | 188 | size = (booke206_page_size_to_tlb(256 * 1024 * 1024) << MAS1_TSIZE_SHIFT); |
| 189 | tlb->mas1 = MAS1_VALID | size; |
| 190 | tlb->mas2 = va & TARGET_PAGE_MASK; |
| 191 | tlb->mas7_3 = pa & TARGET_PAGE_MASK; |
| 192 | tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX; |
Scott Wood | 93dd5e8 | 2011-08-31 11:26:56 +0000 | [diff] [blame] | 193 | |
| 194 | env->tlb_dirty = true; |
Alexander Graf | 3b989d4 | 2011-04-30 23:34:53 +0200 | [diff] [blame] | 195 | } |
| 196 | |
Alexander Graf | 5c145da | 2011-07-22 13:32:29 +0200 | [diff] [blame] | 197 | static void mpc8544ds_cpu_reset_sec(void *opaque) |
| 198 | { |
Andreas Färber | e2684c0 | 2012-03-14 01:38:23 +0100 | [diff] [blame] | 199 | CPUPPCState *env = opaque; |
Alexander Graf | 5c145da | 2011-07-22 13:32:29 +0200 | [diff] [blame] | 200 | |
Andreas Färber | 1bba0dc | 2012-02-08 03:03:33 +0100 | [diff] [blame] | 201 | cpu_state_reset(env); |
Alexander Graf | 5c145da | 2011-07-22 13:32:29 +0200 | [diff] [blame] | 202 | |
| 203 | /* Secondary CPU starts in halted state for now. Needs to change when |
| 204 | implementing non-kernel boot. */ |
| 205 | env->halted = 1; |
| 206 | env->exception_index = EXCP_HLT; |
Alexander Graf | 3b989d4 | 2011-04-30 23:34:53 +0200 | [diff] [blame] | 207 | } |
| 208 | |
| 209 | static void mpc8544ds_cpu_reset(void *opaque) |
| 210 | { |
Andreas Färber | e2684c0 | 2012-03-14 01:38:23 +0100 | [diff] [blame] | 211 | CPUPPCState *env = opaque; |
Alexander Graf | 3b989d4 | 2011-04-30 23:34:53 +0200 | [diff] [blame] | 212 | struct boot_info *bi = env->load_info; |
| 213 | |
Andreas Färber | 1bba0dc | 2012-02-08 03:03:33 +0100 | [diff] [blame] | 214 | cpu_state_reset(env); |
Alexander Graf | 3b989d4 | 2011-04-30 23:34:53 +0200 | [diff] [blame] | 215 | |
| 216 | /* Set initial guest state. */ |
Alexander Graf | 5c145da | 2011-07-22 13:32:29 +0200 | [diff] [blame] | 217 | env->halted = 0; |
Alexander Graf | 3b989d4 | 2011-04-30 23:34:53 +0200 | [diff] [blame] | 218 | env->gpr[1] = (16<<20) - 8; |
| 219 | env->gpr[3] = bi->dt_base; |
| 220 | env->nip = bi->entry; |
| 221 | mmubooke_create_initial_mapping(env, 0, 0); |
| 222 | } |
| 223 | |
Anthony Liguori | c227f09 | 2009-10-01 16:12:16 -0500 | [diff] [blame] | 224 | static void mpc8544ds_init(ram_addr_t ram_size, |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 225 | const char *boot_device, |
| 226 | const char *kernel_filename, |
| 227 | const char *kernel_cmdline, |
| 228 | const char *initrd_filename, |
| 229 | const char *cpu_model) |
| 230 | { |
Richard Henderson | 39186d8 | 2011-08-11 16:07:16 -0700 | [diff] [blame] | 231 | MemoryRegion *address_space_mem = get_system_memory(); |
Avi Kivity | 2646c13 | 2011-10-02 16:43:01 +0200 | [diff] [blame] | 232 | MemoryRegion *ram = g_new(MemoryRegion, 1); |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 233 | PCIBus *pci_bus; |
Andreas Färber | e2684c0 | 2012-03-14 01:38:23 +0100 | [diff] [blame] | 234 | CPUPPCState *env = NULL; |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 235 | uint64_t elf_entry; |
| 236 | uint64_t elf_lowaddr; |
Anthony Liguori | c227f09 | 2009-10-01 16:12:16 -0500 | [diff] [blame] | 237 | target_phys_addr_t entry=0; |
| 238 | target_phys_addr_t loadaddr=UIMAGE_LOAD_BASE; |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 239 | target_long kernel_size=0; |
Liu Yu | 75bb658 | 2010-02-02 16:49:03 +0800 | [diff] [blame] | 240 | target_ulong dt_base = 0; |
| 241 | target_ulong initrd_base = 0; |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 242 | target_long initrd_size=0; |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 243 | int i=0; |
| 244 | unsigned int pci_irq_nrs[4] = {1, 2, 3, 4}; |
Alexander Graf | a915249 | 2011-07-21 01:42:58 +0200 | [diff] [blame] | 245 | qemu_irq **irqs, *mpic; |
Alexander Graf | be13cc7 | 2010-08-31 00:22:28 +0200 | [diff] [blame] | 246 | DeviceState *dev; |
Andreas Färber | e2684c0 | 2012-03-14 01:38:23 +0100 | [diff] [blame] | 247 | CPUPPCState *firstenv = NULL; |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 248 | |
Alexander Graf | e61c36d | 2011-07-21 01:41:16 +0200 | [diff] [blame] | 249 | /* Setup CPUs */ |
Alexander Graf | ef250db | 2011-04-30 23:05:03 +0200 | [diff] [blame] | 250 | if (cpu_model == NULL) { |
| 251 | cpu_model = "e500v2_v30"; |
| 252 | } |
| 253 | |
Alexander Graf | a915249 | 2011-07-21 01:42:58 +0200 | [diff] [blame] | 254 | irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *)); |
| 255 | irqs[0] = g_malloc0(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB); |
Alexander Graf | e61c36d | 2011-07-21 01:41:16 +0200 | [diff] [blame] | 256 | for (i = 0; i < smp_cpus; i++) { |
| 257 | qemu_irq *input; |
| 258 | env = cpu_ppc_init(cpu_model); |
| 259 | if (!env) { |
| 260 | fprintf(stderr, "Unable to initialize CPU!\n"); |
| 261 | exit(1); |
| 262 | } |
| 263 | |
| 264 | if (!firstenv) { |
| 265 | firstenv = env; |
| 266 | } |
| 267 | |
Alexander Graf | a915249 | 2011-07-21 01:42:58 +0200 | [diff] [blame] | 268 | irqs[i] = irqs[0] + (i * OPENPIC_OUTPUT_NB); |
| 269 | input = (qemu_irq *)env->irq_inputs; |
| 270 | irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT]; |
| 271 | irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT]; |
Alexander Graf | e61c36d | 2011-07-21 01:41:16 +0200 | [diff] [blame] | 272 | env->spr[SPR_BOOKE_PIR] = env->cpu_index = i; |
| 273 | |
Fabien Chouteau | ddd1055 | 2011-09-13 04:00:32 +0000 | [diff] [blame] | 274 | ppc_booke_timers_init(env, 400000000, PPC_TIMER_E500); |
Alexander Graf | e61c36d | 2011-07-21 01:41:16 +0200 | [diff] [blame] | 275 | |
| 276 | /* Register reset handler */ |
Alexander Graf | 5c145da | 2011-07-22 13:32:29 +0200 | [diff] [blame] | 277 | if (!i) { |
| 278 | /* Primary CPU */ |
| 279 | struct boot_info *boot_info; |
| 280 | boot_info = g_malloc0(sizeof(struct boot_info)); |
| 281 | qemu_register_reset(mpc8544ds_cpu_reset, env); |
| 282 | env->load_info = boot_info; |
| 283 | } else { |
| 284 | /* Secondary CPUs */ |
| 285 | qemu_register_reset(mpc8544ds_cpu_reset_sec, env); |
| 286 | } |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 287 | } |
| 288 | |
Alexander Graf | e61c36d | 2011-07-21 01:41:16 +0200 | [diff] [blame] | 289 | env = firstenv; |
Alexander Graf | 3b989d4 | 2011-04-30 23:34:53 +0200 | [diff] [blame] | 290 | |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 291 | /* Fixup Memory size on a alignment boundary */ |
| 292 | ram_size &= ~(RAM_SIZES_ALIGN - 1); |
| 293 | |
| 294 | /* Register Memory */ |
Avi Kivity | c5705a7 | 2011-12-20 15:59:12 +0200 | [diff] [blame] | 295 | memory_region_init_ram(ram, "mpc8544ds.ram", ram_size); |
| 296 | vmstate_register_ram_global(ram); |
Avi Kivity | 2646c13 | 2011-10-02 16:43:01 +0200 | [diff] [blame] | 297 | memory_region_add_subregion(address_space_mem, 0, ram); |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 298 | |
| 299 | /* MPIC */ |
Avi Kivity | df2921d | 2011-10-09 13:11:50 +0200 | [diff] [blame] | 300 | mpic = mpic_init(address_space_mem, MPC8544_MPIC_REGS_BASE, |
| 301 | smp_cpus, irqs, NULL); |
Alexander Graf | a915249 | 2011-07-21 01:42:58 +0200 | [diff] [blame] | 302 | |
| 303 | if (!mpic) { |
| 304 | cpu_abort(env, "MPIC failed to initialize\n"); |
| 305 | } |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 306 | |
| 307 | /* Serial */ |
Blue Swirl | 2d48377 | 2010-03-21 19:47:11 +0000 | [diff] [blame] | 308 | if (serial_hds[0]) { |
Richard Henderson | 39186d8 | 2011-08-11 16:07:16 -0700 | [diff] [blame] | 309 | serial_mm_init(address_space_mem, MPC8544_SERIAL0_REGS_BASE, |
Blue Swirl | 49a2942 | 2010-10-13 18:41:29 +0000 | [diff] [blame] | 310 | 0, mpic[12+26], 399193, |
Richard Henderson | 2ff0c7c | 2011-08-11 16:07:15 -0700 | [diff] [blame] | 311 | serial_hds[0], DEVICE_BIG_ENDIAN); |
Blue Swirl | 2d48377 | 2010-03-21 19:47:11 +0000 | [diff] [blame] | 312 | } |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 313 | |
Blue Swirl | 2d48377 | 2010-03-21 19:47:11 +0000 | [diff] [blame] | 314 | if (serial_hds[1]) { |
Richard Henderson | 39186d8 | 2011-08-11 16:07:16 -0700 | [diff] [blame] | 315 | serial_mm_init(address_space_mem, MPC8544_SERIAL1_REGS_BASE, |
Blue Swirl | 49a2942 | 2010-10-13 18:41:29 +0000 | [diff] [blame] | 316 | 0, mpic[12+26], 399193, |
Richard Henderson | 2ff0c7c | 2011-08-11 16:07:15 -0700 | [diff] [blame] | 317 | serial_hds[0], DEVICE_BIG_ENDIAN); |
Blue Swirl | 2d48377 | 2010-03-21 19:47:11 +0000 | [diff] [blame] | 318 | } |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 319 | |
Alexander Graf | b0fb842 | 2011-06-02 13:53:40 +0200 | [diff] [blame] | 320 | /* General Utility device */ |
| 321 | sysbus_create_simple("mpc8544-guts", MPC8544_UTIL_BASE, NULL); |
| 322 | |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 323 | /* PCI */ |
Alexander Graf | be13cc7 | 2010-08-31 00:22:28 +0200 | [diff] [blame] | 324 | dev = sysbus_create_varargs("e500-pcihost", MPC8544_PCI_REGS_BASE, |
| 325 | mpic[pci_irq_nrs[0]], mpic[pci_irq_nrs[1]], |
| 326 | mpic[pci_irq_nrs[2]], mpic[pci_irq_nrs[3]], |
| 327 | NULL); |
Alexander Graf | d461e3b | 2011-05-27 03:23:26 +0200 | [diff] [blame] | 328 | pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0"); |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 329 | if (!pci_bus) |
| 330 | printf("couldn't create PCI controller!\n"); |
| 331 | |
Alexander Graf | 968d683 | 2010-12-08 12:05:49 +0100 | [diff] [blame] | 332 | isa_mmio_init(MPC8544_PCI_IO, MPC8544_PCI_IOLEN); |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 333 | |
| 334 | if (pci_bus) { |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 335 | /* Register network interfaces. */ |
| 336 | for (i = 0; i < nb_nics; i++) { |
Markus Armbruster | 07caea3 | 2009-09-25 03:53:51 +0200 | [diff] [blame] | 337 | pci_nic_init_nofail(&nd_table[i], "virtio", NULL); |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 338 | } |
| 339 | } |
| 340 | |
Alexander Graf | 5c145da | 2011-07-22 13:32:29 +0200 | [diff] [blame] | 341 | /* Register spinning region */ |
| 342 | sysbus_create_simple("e500-spin", MPC8544_SPIN_BASE, NULL); |
| 343 | |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 344 | /* Load kernel. */ |
| 345 | if (kernel_filename) { |
| 346 | kernel_size = load_uimage(kernel_filename, &entry, &loadaddr, NULL); |
| 347 | if (kernel_size < 0) { |
Aurelien Jarno | 409dbce | 2010-03-14 21:20:59 +0100 | [diff] [blame] | 348 | kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry, |
| 349 | &elf_lowaddr, NULL, 1, ELF_MACHINE, 0); |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 350 | entry = elf_entry; |
| 351 | loadaddr = elf_lowaddr; |
| 352 | } |
| 353 | /* XXX try again as binary */ |
| 354 | if (kernel_size < 0) { |
| 355 | fprintf(stderr, "qemu: could not load kernel '%s'\n", |
| 356 | kernel_filename); |
| 357 | exit(1); |
| 358 | } |
| 359 | } |
| 360 | |
| 361 | /* Load initrd. */ |
| 362 | if (initrd_filename) { |
Liu Yu | 75bb658 | 2010-02-02 16:49:03 +0800 | [diff] [blame] | 363 | initrd_base = (kernel_size + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK; |
pbrook | d758525 | 2009-04-10 03:36:49 +0000 | [diff] [blame] | 364 | initrd_size = load_image_targphys(initrd_filename, initrd_base, |
| 365 | ram_size - initrd_base); |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 366 | |
| 367 | if (initrd_size < 0) { |
| 368 | fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", |
| 369 | initrd_filename); |
| 370 | exit(1); |
| 371 | } |
| 372 | } |
| 373 | |
| 374 | /* If we're loading a kernel directly, we must load the device tree too. */ |
| 375 | if (kernel_filename) { |
Alexander Graf | 5c145da | 2011-07-22 13:32:29 +0200 | [diff] [blame] | 376 | struct boot_info *boot_info; |
| 377 | |
Alexander Graf | 3b989d4 | 2011-04-30 23:34:53 +0200 | [diff] [blame] | 378 | #ifndef CONFIG_FDT |
| 379 | cpu_abort(env, "Compiled without FDT support - can't load kernel\n"); |
| 380 | #endif |
Liu Yu | 75bb658 | 2010-02-02 16:49:03 +0800 | [diff] [blame] | 381 | dt_base = (kernel_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK; |
Alexander Graf | 5de6b46 | 2011-06-15 23:34:04 +0200 | [diff] [blame] | 382 | if (mpc8544_load_device_tree(env, dt_base, ram_size, |
Liu Yu | 04088ad | 2010-02-02 16:49:02 +0800 | [diff] [blame] | 383 | initrd_base, initrd_size, kernel_cmdline) < 0) { |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 384 | fprintf(stderr, "couldn't load device tree\n"); |
| 385 | exit(1); |
| 386 | } |
| 387 | |
Alexander Graf | e61c36d | 2011-07-21 01:41:16 +0200 | [diff] [blame] | 388 | boot_info = env->load_info; |
Alexander Graf | 3b989d4 | 2011-04-30 23:34:53 +0200 | [diff] [blame] | 389 | boot_info->entry = entry; |
| 390 | boot_info->dt_base = dt_base; |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 391 | } |
| 392 | |
Alexander Graf | 3b989d4 | 2011-04-30 23:34:53 +0200 | [diff] [blame] | 393 | if (kvm_enabled()) { |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 394 | kvmppc_init(); |
Alexander Graf | 3b989d4 | 2011-04-30 23:34:53 +0200 | [diff] [blame] | 395 | } |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 396 | } |
| 397 | |
Anthony Liguori | f80f9ec | 2009-05-20 18:38:09 -0500 | [diff] [blame] | 398 | static QEMUMachine mpc8544ds_machine = { |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 399 | .name = "mpc8544ds", |
| 400 | .desc = "mpc8544ds", |
| 401 | .init = mpc8544ds_init, |
Alexander Graf | a2a6742 | 2011-07-21 01:45:37 +0200 | [diff] [blame] | 402 | .max_cpus = 15, |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 403 | }; |
Anthony Liguori | f80f9ec | 2009-05-20 18:38:09 -0500 | [diff] [blame] | 404 | |
| 405 | static void mpc8544ds_machine_init(void) |
| 406 | { |
| 407 | qemu_register_machine(&mpc8544ds_machine); |
| 408 | } |
| 409 | |
| 410 | machine_init(mpc8544ds_machine_init); |