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