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 | { |
| 177 | return (ffs(size >> 10) - 1) >> 1; |
| 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; |
Alexander Graf | 3b989d4 | 2011-04-30 23:34:53 +0200 | [diff] [blame] | 192 | } |
| 193 | |
Alexander Graf | 5c145da | 2011-07-22 13:32:29 +0200 | [diff] [blame] | 194 | static void mpc8544ds_cpu_reset_sec(void *opaque) |
| 195 | { |
| 196 | CPUState *env = opaque; |
| 197 | |
| 198 | cpu_reset(env); |
| 199 | |
| 200 | /* Secondary CPU starts in halted state for now. Needs to change when |
| 201 | implementing non-kernel boot. */ |
| 202 | env->halted = 1; |
| 203 | env->exception_index = EXCP_HLT; |
| 204 | } |
| 205 | |
Alexander Graf | 3b989d4 | 2011-04-30 23:34:53 +0200 | [diff] [blame] | 206 | static void mpc8544ds_cpu_reset(void *opaque) |
| 207 | { |
| 208 | CPUState *env = opaque; |
| 209 | struct boot_info *bi = env->load_info; |
| 210 | |
| 211 | cpu_reset(env); |
| 212 | |
| 213 | /* Set initial guest state. */ |
Alexander Graf | 5c145da | 2011-07-22 13:32:29 +0200 | [diff] [blame] | 214 | env->halted = 0; |
Alexander Graf | 3b989d4 | 2011-04-30 23:34:53 +0200 | [diff] [blame] | 215 | env->gpr[1] = (16<<20) - 8; |
| 216 | env->gpr[3] = bi->dt_base; |
| 217 | env->nip = bi->entry; |
| 218 | mmubooke_create_initial_mapping(env, 0, 0); |
| 219 | } |
| 220 | |
Anthony Liguori | c227f09 | 2009-10-01 16:12:16 -0500 | [diff] [blame] | 221 | static void mpc8544ds_init(ram_addr_t ram_size, |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 222 | const char *boot_device, |
| 223 | const char *kernel_filename, |
| 224 | const char *kernel_cmdline, |
| 225 | const char *initrd_filename, |
| 226 | const char *cpu_model) |
| 227 | { |
| 228 | PCIBus *pci_bus; |
Alexander Graf | e61c36d | 2011-07-21 01:41:16 +0200 | [diff] [blame] | 229 | CPUState *env = NULL; |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 230 | uint64_t elf_entry; |
| 231 | uint64_t elf_lowaddr; |
Anthony Liguori | c227f09 | 2009-10-01 16:12:16 -0500 | [diff] [blame] | 232 | target_phys_addr_t entry=0; |
| 233 | target_phys_addr_t loadaddr=UIMAGE_LOAD_BASE; |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 234 | target_long kernel_size=0; |
Liu Yu | 75bb658 | 2010-02-02 16:49:03 +0800 | [diff] [blame] | 235 | target_ulong dt_base = 0; |
| 236 | target_ulong initrd_base = 0; |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 237 | target_long initrd_size=0; |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 238 | int i=0; |
| 239 | unsigned int pci_irq_nrs[4] = {1, 2, 3, 4}; |
Alexander Graf | a915249 | 2011-07-21 01:42:58 +0200 | [diff] [blame] | 240 | qemu_irq **irqs, *mpic; |
Alexander Graf | be13cc7 | 2010-08-31 00:22:28 +0200 | [diff] [blame] | 241 | DeviceState *dev; |
Alexander Graf | e61c36d | 2011-07-21 01:41:16 +0200 | [diff] [blame] | 242 | CPUState *firstenv = NULL; |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 243 | |
Alexander Graf | e61c36d | 2011-07-21 01:41:16 +0200 | [diff] [blame] | 244 | /* Setup CPUs */ |
Alexander Graf | ef250db | 2011-04-30 23:05:03 +0200 | [diff] [blame] | 245 | if (cpu_model == NULL) { |
| 246 | cpu_model = "e500v2_v30"; |
| 247 | } |
| 248 | |
Alexander Graf | a915249 | 2011-07-21 01:42:58 +0200 | [diff] [blame] | 249 | irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *)); |
| 250 | irqs[0] = g_malloc0(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB); |
Alexander Graf | e61c36d | 2011-07-21 01:41:16 +0200 | [diff] [blame] | 251 | for (i = 0; i < smp_cpus; i++) { |
| 252 | qemu_irq *input; |
| 253 | env = cpu_ppc_init(cpu_model); |
| 254 | if (!env) { |
| 255 | fprintf(stderr, "Unable to initialize CPU!\n"); |
| 256 | exit(1); |
| 257 | } |
| 258 | |
| 259 | if (!firstenv) { |
| 260 | firstenv = env; |
| 261 | } |
| 262 | |
Alexander Graf | a915249 | 2011-07-21 01:42:58 +0200 | [diff] [blame] | 263 | irqs[i] = irqs[0] + (i * OPENPIC_OUTPUT_NB); |
| 264 | input = (qemu_irq *)env->irq_inputs; |
| 265 | irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT]; |
| 266 | irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT]; |
Alexander Graf | e61c36d | 2011-07-21 01:41:16 +0200 | [diff] [blame] | 267 | env->spr[SPR_BOOKE_PIR] = env->cpu_index = i; |
| 268 | |
| 269 | /* XXX register timer? */ |
| 270 | ppc_emb_timers_init(env, 400000000, PPC_INTERRUPT_DECR); |
| 271 | ppc_dcr_init(env, NULL, NULL); |
| 272 | /* XXX Enable DEC interrupts - probably wrong in the backend */ |
| 273 | env->spr[SPR_40x_TCR] = 1 << 26; |
| 274 | |
| 275 | /* Register reset handler */ |
Alexander Graf | 5c145da | 2011-07-22 13:32:29 +0200 | [diff] [blame] | 276 | if (!i) { |
| 277 | /* Primary CPU */ |
| 278 | struct boot_info *boot_info; |
| 279 | boot_info = g_malloc0(sizeof(struct boot_info)); |
| 280 | qemu_register_reset(mpc8544ds_cpu_reset, env); |
| 281 | env->load_info = boot_info; |
| 282 | } else { |
| 283 | /* Secondary CPUs */ |
| 284 | qemu_register_reset(mpc8544ds_cpu_reset_sec, env); |
| 285 | } |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 286 | } |
| 287 | |
Alexander Graf | e61c36d | 2011-07-21 01:41:16 +0200 | [diff] [blame] | 288 | env = firstenv; |
Alexander Graf | 3b989d4 | 2011-04-30 23:34:53 +0200 | [diff] [blame] | 289 | |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 290 | /* Fixup Memory size on a alignment boundary */ |
| 291 | ram_size &= ~(RAM_SIZES_ALIGN - 1); |
| 292 | |
| 293 | /* Register Memory */ |
Alex Williamson | 1724f04 | 2010-06-25 11:09:35 -0600 | [diff] [blame] | 294 | cpu_register_physical_memory(0, ram_size, qemu_ram_alloc(NULL, |
| 295 | "mpc8544ds.ram", ram_size)); |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 296 | |
| 297 | /* MPIC */ |
Alexander Graf | a915249 | 2011-07-21 01:42:58 +0200 | [diff] [blame] | 298 | mpic = mpic_init(MPC8544_MPIC_REGS_BASE, smp_cpus, irqs, NULL); |
| 299 | |
| 300 | if (!mpic) { |
| 301 | cpu_abort(env, "MPIC failed to initialize\n"); |
| 302 | } |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 303 | |
| 304 | /* Serial */ |
Blue Swirl | 2d48377 | 2010-03-21 19:47:11 +0000 | [diff] [blame] | 305 | if (serial_hds[0]) { |
Blue Swirl | 49a2942 | 2010-10-13 18:41:29 +0000 | [diff] [blame] | 306 | serial_mm_init(MPC8544_SERIAL0_REGS_BASE, |
| 307 | 0, mpic[12+26], 399193, |
| 308 | serial_hds[0], 1, 1); |
Blue Swirl | 2d48377 | 2010-03-21 19:47:11 +0000 | [diff] [blame] | 309 | } |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 310 | |
Blue Swirl | 2d48377 | 2010-03-21 19:47:11 +0000 | [diff] [blame] | 311 | if (serial_hds[1]) { |
Blue Swirl | 49a2942 | 2010-10-13 18:41:29 +0000 | [diff] [blame] | 312 | serial_mm_init(MPC8544_SERIAL1_REGS_BASE, |
| 313 | 0, mpic[12+26], 399193, |
| 314 | serial_hds[0], 1, 1); |
Blue Swirl | 2d48377 | 2010-03-21 19:47:11 +0000 | [diff] [blame] | 315 | } |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 316 | |
Alexander Graf | b0fb842 | 2011-06-02 13:53:40 +0200 | [diff] [blame] | 317 | /* General Utility device */ |
| 318 | sysbus_create_simple("mpc8544-guts", MPC8544_UTIL_BASE, NULL); |
| 319 | |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 320 | /* PCI */ |
Alexander Graf | be13cc7 | 2010-08-31 00:22:28 +0200 | [diff] [blame] | 321 | dev = sysbus_create_varargs("e500-pcihost", MPC8544_PCI_REGS_BASE, |
| 322 | mpic[pci_irq_nrs[0]], mpic[pci_irq_nrs[1]], |
| 323 | mpic[pci_irq_nrs[2]], mpic[pci_irq_nrs[3]], |
| 324 | NULL); |
Alexander Graf | d461e3b | 2011-05-27 03:23:26 +0200 | [diff] [blame] | 325 | pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0"); |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 326 | if (!pci_bus) |
| 327 | printf("couldn't create PCI controller!\n"); |
| 328 | |
Alexander Graf | 968d683 | 2010-12-08 12:05:49 +0100 | [diff] [blame] | 329 | isa_mmio_init(MPC8544_PCI_IO, MPC8544_PCI_IOLEN); |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 330 | |
| 331 | if (pci_bus) { |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 332 | /* Register network interfaces. */ |
| 333 | for (i = 0; i < nb_nics; i++) { |
Markus Armbruster | 07caea3 | 2009-09-25 03:53:51 +0200 | [diff] [blame] | 334 | pci_nic_init_nofail(&nd_table[i], "virtio", NULL); |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 335 | } |
| 336 | } |
| 337 | |
Alexander Graf | 5c145da | 2011-07-22 13:32:29 +0200 | [diff] [blame] | 338 | /* Register spinning region */ |
| 339 | sysbus_create_simple("e500-spin", MPC8544_SPIN_BASE, NULL); |
| 340 | |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 341 | /* Load kernel. */ |
| 342 | if (kernel_filename) { |
| 343 | kernel_size = load_uimage(kernel_filename, &entry, &loadaddr, NULL); |
| 344 | if (kernel_size < 0) { |
Aurelien Jarno | 409dbce | 2010-03-14 21:20:59 +0100 | [diff] [blame] | 345 | kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry, |
| 346 | &elf_lowaddr, NULL, 1, ELF_MACHINE, 0); |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 347 | entry = elf_entry; |
| 348 | loadaddr = elf_lowaddr; |
| 349 | } |
| 350 | /* XXX try again as binary */ |
| 351 | if (kernel_size < 0) { |
| 352 | fprintf(stderr, "qemu: could not load kernel '%s'\n", |
| 353 | kernel_filename); |
| 354 | exit(1); |
| 355 | } |
| 356 | } |
| 357 | |
| 358 | /* Load initrd. */ |
| 359 | if (initrd_filename) { |
Liu Yu | 75bb658 | 2010-02-02 16:49:03 +0800 | [diff] [blame] | 360 | initrd_base = (kernel_size + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK; |
pbrook | d758525 | 2009-04-10 03:36:49 +0000 | [diff] [blame] | 361 | initrd_size = load_image_targphys(initrd_filename, initrd_base, |
| 362 | ram_size - initrd_base); |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 363 | |
| 364 | if (initrd_size < 0) { |
| 365 | fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", |
| 366 | initrd_filename); |
| 367 | exit(1); |
| 368 | } |
| 369 | } |
| 370 | |
| 371 | /* If we're loading a kernel directly, we must load the device tree too. */ |
| 372 | if (kernel_filename) { |
Alexander Graf | 5c145da | 2011-07-22 13:32:29 +0200 | [diff] [blame] | 373 | struct boot_info *boot_info; |
| 374 | |
Alexander Graf | 3b989d4 | 2011-04-30 23:34:53 +0200 | [diff] [blame] | 375 | #ifndef CONFIG_FDT |
| 376 | cpu_abort(env, "Compiled without FDT support - can't load kernel\n"); |
| 377 | #endif |
Liu Yu | 75bb658 | 2010-02-02 16:49:03 +0800 | [diff] [blame] | 378 | dt_base = (kernel_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK; |
Alexander Graf | 5de6b46 | 2011-06-15 23:34:04 +0200 | [diff] [blame] | 379 | if (mpc8544_load_device_tree(env, dt_base, ram_size, |
Liu Yu | 04088ad | 2010-02-02 16:49:02 +0800 | [diff] [blame] | 380 | initrd_base, initrd_size, kernel_cmdline) < 0) { |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 381 | fprintf(stderr, "couldn't load device tree\n"); |
| 382 | exit(1); |
| 383 | } |
| 384 | |
Alexander Graf | e61c36d | 2011-07-21 01:41:16 +0200 | [diff] [blame] | 385 | boot_info = env->load_info; |
Alexander Graf | 3b989d4 | 2011-04-30 23:34:53 +0200 | [diff] [blame] | 386 | boot_info->entry = entry; |
| 387 | boot_info->dt_base = dt_base; |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 388 | } |
| 389 | |
Alexander Graf | 3b989d4 | 2011-04-30 23:34:53 +0200 | [diff] [blame] | 390 | if (kvm_enabled()) { |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 391 | kvmppc_init(); |
Alexander Graf | 3b989d4 | 2011-04-30 23:34:53 +0200 | [diff] [blame] | 392 | } |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 393 | } |
| 394 | |
Anthony Liguori | f80f9ec | 2009-05-20 18:38:09 -0500 | [diff] [blame] | 395 | static QEMUMachine mpc8544ds_machine = { |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 396 | .name = "mpc8544ds", |
| 397 | .desc = "mpc8544ds", |
| 398 | .init = mpc8544ds_init, |
Alexander Graf | a2a6742 | 2011-07-21 01:45:37 +0200 | [diff] [blame^] | 399 | .max_cpus = 15, |
aurel32 | 1db09b8 | 2009-03-02 16:42:42 +0000 | [diff] [blame] | 400 | }; |
Anthony Liguori | f80f9ec | 2009-05-20 18:38:09 -0500 | [diff] [blame] | 401 | |
| 402 | static void mpc8544ds_machine_init(void) |
| 403 | { |
| 404 | qemu_register_machine(&mpc8544ds_machine); |
| 405 | } |
| 406 | |
| 407 | machine_init(mpc8544ds_machine_init); |