|
|
1.1 root 1: /*
2: * Qemu PowerPC MPC8544DS board emualtion
3: *
4: * Copyright (C) 2009 Freescale Semiconductor, Inc. All rights reserved.
5: *
6: * Author: Yu Liu, <[email protected]>
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:
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"
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"
1.1.1.6 root 29: #include "ppc.h"
1.1.1.3 root 30: #include "loader.h"
31: #include "elf.h"
1.1.1.6 root 32: #include "sysbus.h"
1.1.1.7 ! root 33: #include "exec-memory.h"
1.1 root 34:
35: #define BINARY_DEVICE_TREE_FILE "mpc8544ds.dtb"
36: #define UIMAGE_LOAD_BASE 0
1.1.1.4 root 37: #define DTC_LOAD_PAD 0x500000
38: #define DTC_PAD_MASK 0xFFFFF
39: #define INITRD_LOAD_PAD 0x2000000
40: #define INITRD_PAD_MASK 0xFFFFFF
1.1 root 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
1.1.1.6 root 52: #define MPC8544_UTIL_BASE (MPC8544_CCSRBAR_BASE + 0xe0000)
1.1.1.7 ! root 53: #define MPC8544_SPIN_BASE 0xEF000000
1.1.1.6 root 54:
55: struct boot_info
56: {
57: uint32_t dt_base;
58: uint32_t entry;
59: };
1.1 root 60:
1.1.1.6 root 61: static int mpc8544_load_device_tree(CPUState *env,
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)
1.1 root 67: {
1.1.1.4 root 68: int ret = -1;
1.1.1.3 root 69: #ifdef CONFIG_FDT
1.1.1.6 root 70: uint32_t mem_reg_property[] = {0, cpu_to_be32(ramsize)};
1.1.1.2 root 71: char *filename;
72: int fdt_size;
1.1.1.4 root 73: void *fdt;
1.1.1.6 root 74: uint8_t hypercall[16];
1.1.1.7 ! root 75: uint32_t clock_freq = 400000000;
! 76: uint32_t tb_freq = 400000000;
! 77: int i;
1.1 root 78:
1.1.1.2 root 79: filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
80: if (!filename) {
81: goto out;
82: }
83: fdt = load_device_tree(filename, &fdt_size);
1.1.1.7 ! root 84: g_free(filename);
1.1.1.2 root 85: if (fdt == NULL) {
1.1 root 86: goto out;
1.1.1.2 root 87: }
1.1 root 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:
1.1.1.6 root 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: }
1.1 root 101:
1.1.1.6 root 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: }
1.1 root 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()) {
1.1.1.7 ! root 115: /* Read out host's frequencies */
! 116: clock_freq = kvmppc_get_clockfreq();
! 117: tb_freq = kvmppc_get_tbfreq();
1.1.1.6 root 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));
1.1.1.7 ! root 125: }
1.1.1.6 root 126:
1.1.1.7 ! root 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--) {
! 130: char cpu_name[128];
! 131: uint64_t cpu_release_addr = cpu_to_be64(MPC8544_SPIN_BASE + (i * 0x20));
! 132:
! 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);
! 145: qemu_devtree_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq);
! 146: qemu_devtree_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq);
! 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: }
1.1 root 164: }
165:
1.1.1.4 root 166: ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
1.1.1.7 ! root 167: g_free(fdt);
1.1.1.2 root 168:
1.1 root 169: out:
170: #endif
171:
1.1.1.4 root 172: return ret;
1.1 root 173: }
174:
1.1.1.6 root 175: /* Create -kernel TLB entries for BookE, linearly spanning 256MB. */
176: static inline target_phys_addr_t booke206_page_size_to_tlb(uint64_t size)
177: {
1.1.1.7 ! root 178: return ffs(size >> 10) - 1;
1.1.1.6 root 179: }
180:
181: static void mmubooke_create_initial_mapping(CPUState *env,
182: target_ulong va,
183: target_phys_addr_t pa)
184: {
185: ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0);
186: target_phys_addr_t size;
187:
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;
1.1.1.7 ! root 193:
! 194: env->tlb_dirty = true;
! 195: }
! 196:
! 197: static void mpc8544ds_cpu_reset_sec(void *opaque)
! 198: {
! 199: CPUState *env = opaque;
! 200:
! 201: cpu_reset(env);
! 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;
1.1.1.6 root 207: }
208:
209: static void mpc8544ds_cpu_reset(void *opaque)
210: {
211: CPUState *env = opaque;
212: struct boot_info *bi = env->load_info;
213:
214: cpu_reset(env);
215:
216: /* Set initial guest state. */
1.1.1.7 ! root 217: env->halted = 0;
1.1.1.6 root 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:
1.1.1.2 root 224: static void mpc8544ds_init(ram_addr_t ram_size,
1.1 root 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: {
1.1.1.7 ! root 231: MemoryRegion *address_space_mem = get_system_memory();
! 232: MemoryRegion *ram = g_new(MemoryRegion, 1);
1.1 root 233: PCIBus *pci_bus;
1.1.1.7 ! root 234: CPUState *env = NULL;
1.1 root 235: uint64_t elf_entry;
236: uint64_t elf_lowaddr;
1.1.1.3 root 237: target_phys_addr_t entry=0;
238: target_phys_addr_t loadaddr=UIMAGE_LOAD_BASE;
1.1 root 239: target_long kernel_size=0;
1.1.1.4 root 240: target_ulong dt_base = 0;
241: target_ulong initrd_base = 0;
1.1 root 242: target_long initrd_size=0;
243: int i=0;
244: unsigned int pci_irq_nrs[4] = {1, 2, 3, 4};
1.1.1.7 ! root 245: qemu_irq **irqs, *mpic;
1.1.1.6 root 246: DeviceState *dev;
1.1.1.7 ! root 247: CPUState *firstenv = NULL;
1.1 root 248:
1.1.1.7 ! root 249: /* Setup CPUs */
1.1.1.6 root 250: if (cpu_model == NULL) {
251: cpu_model = "e500v2_v30";
252: }
253:
1.1.1.7 ! root 254: irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *));
! 255: irqs[0] = g_malloc0(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
! 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: }
1.1 root 263:
1.1.1.7 ! root 264: if (!firstenv) {
! 265: firstenv = env;
! 266: }
! 267:
! 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];
! 272: env->spr[SPR_BOOKE_PIR] = env->cpu_index = i;
! 273:
! 274: ppc_booke_timers_init(env, 400000000, PPC_TIMER_E500);
! 275:
! 276: /* Register reset handler */
! 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: }
! 287: }
1.1.1.6 root 288:
1.1.1.7 ! root 289: env = firstenv;
1.1.1.6 root 290:
1.1 root 291: /* Fixup Memory size on a alignment boundary */
292: ram_size &= ~(RAM_SIZES_ALIGN - 1);
293:
294: /* Register Memory */
1.1.1.7 ! root 295: memory_region_init_ram(ram, NULL, "mpc8544ds.ram", ram_size);
! 296: memory_region_add_subregion(address_space_mem, 0, ram);
1.1 root 297:
298: /* MPIC */
1.1.1.7 ! root 299: mpic = mpic_init(address_space_mem, MPC8544_MPIC_REGS_BASE,
! 300: smp_cpus, irqs, NULL);
! 301:
! 302: if (!mpic) {
! 303: cpu_abort(env, "MPIC failed to initialize\n");
! 304: }
1.1 root 305:
306: /* Serial */
1.1.1.4 root 307: if (serial_hds[0]) {
1.1.1.7 ! root 308: serial_mm_init(address_space_mem, MPC8544_SERIAL0_REGS_BASE,
1.1.1.5 root 309: 0, mpic[12+26], 399193,
1.1.1.7 ! root 310: serial_hds[0], DEVICE_BIG_ENDIAN);
1.1.1.4 root 311: }
1.1 root 312:
1.1.1.4 root 313: if (serial_hds[1]) {
1.1.1.7 ! root 314: serial_mm_init(address_space_mem, MPC8544_SERIAL1_REGS_BASE,
1.1.1.5 root 315: 0, mpic[12+26], 399193,
1.1.1.7 ! root 316: serial_hds[0], DEVICE_BIG_ENDIAN);
1.1.1.4 root 317: }
1.1 root 318:
1.1.1.6 root 319: /* General Utility device */
320: sysbus_create_simple("mpc8544-guts", MPC8544_UTIL_BASE, NULL);
321:
1.1 root 322: /* PCI */
1.1.1.6 root 323: dev = sysbus_create_varargs("e500-pcihost", MPC8544_PCI_REGS_BASE,
324: mpic[pci_irq_nrs[0]], mpic[pci_irq_nrs[1]],
325: mpic[pci_irq_nrs[2]], mpic[pci_irq_nrs[3]],
326: NULL);
327: pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
1.1 root 328: if (!pci_bus)
329: printf("couldn't create PCI controller!\n");
330:
1.1.1.5 root 331: isa_mmio_init(MPC8544_PCI_IO, MPC8544_PCI_IOLEN);
1.1 root 332:
333: if (pci_bus) {
334: /* Register network interfaces. */
335: for (i = 0; i < nb_nics; i++) {
1.1.1.3 root 336: pci_nic_init_nofail(&nd_table[i], "virtio", NULL);
1.1 root 337: }
338: }
339:
1.1.1.7 ! root 340: /* Register spinning region */
! 341: sysbus_create_simple("e500-spin", MPC8544_SPIN_BASE, NULL);
! 342:
1.1 root 343: /* Load kernel. */
344: if (kernel_filename) {
345: kernel_size = load_uimage(kernel_filename, &entry, &loadaddr, NULL);
346: if (kernel_size < 0) {
1.1.1.4 root 347: kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry,
348: &elf_lowaddr, NULL, 1, ELF_MACHINE, 0);
1.1 root 349: entry = elf_entry;
350: loadaddr = elf_lowaddr;
351: }
352: /* XXX try again as binary */
353: if (kernel_size < 0) {
354: fprintf(stderr, "qemu: could not load kernel '%s'\n",
355: kernel_filename);
356: exit(1);
357: }
358: }
359:
360: /* Load initrd. */
361: if (initrd_filename) {
1.1.1.4 root 362: initrd_base = (kernel_size + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK;
1.1.1.2 root 363: initrd_size = load_image_targphys(initrd_filename, initrd_base,
364: ram_size - initrd_base);
1.1 root 365:
366: if (initrd_size < 0) {
367: fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
368: initrd_filename);
369: exit(1);
370: }
371: }
372:
373: /* If we're loading a kernel directly, we must load the device tree too. */
374: if (kernel_filename) {
1.1.1.7 ! root 375: struct boot_info *boot_info;
! 376:
1.1.1.6 root 377: #ifndef CONFIG_FDT
378: cpu_abort(env, "Compiled without FDT support - can't load kernel\n");
379: #endif
1.1.1.4 root 380: dt_base = (kernel_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
1.1.1.6 root 381: if (mpc8544_load_device_tree(env, dt_base, ram_size,
1.1.1.4 root 382: initrd_base, initrd_size, kernel_cmdline) < 0) {
1.1 root 383: fprintf(stderr, "couldn't load device tree\n");
384: exit(1);
385: }
386:
1.1.1.7 ! root 387: boot_info = env->load_info;
1.1.1.6 root 388: boot_info->entry = entry;
389: boot_info->dt_base = dt_base;
1.1 root 390: }
391:
1.1.1.6 root 392: if (kvm_enabled()) {
1.1 root 393: kvmppc_init();
1.1.1.6 root 394: }
1.1 root 395: }
396:
1.1.1.2 root 397: static QEMUMachine mpc8544ds_machine = {
1.1 root 398: .name = "mpc8544ds",
399: .desc = "mpc8544ds",
400: .init = mpc8544ds_init,
1.1.1.7 ! root 401: .max_cpus = 15,
1.1 root 402: };
1.1.1.2 root 403:
404: static void mpc8544ds_machine_init(void)
405: {
406: qemu_register_machine(&mpc8544ds_machine);
407: }
408:
409: machine_init(mpc8544ds_machine_init);
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.