|
|
1.1 root 1: /* 1.1.1.8 ! root 2: * QEMU PowerPC MPC8544DS board emulation 1.1 root 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.8 ! root 61: static int mpc8544_load_device_tree(CPUPPCState *env, 1.1.1.6 root 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: 1.1.1.8 ! root 181: static void mmubooke_create_initial_mapping(CPUPPCState *env, 1.1.1.6 root 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: { 1.1.1.8 ! root 199: CPUPPCState *env = opaque; 1.1.1.7 root 200: 1.1.1.8 ! root 201: cpu_state_reset(env); 1.1.1.7 root 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: { 1.1.1.8 ! root 211: CPUPPCState *env = opaque; 1.1.1.6 root 212: struct boot_info *bi = env->load_info; 213: 1.1.1.8 ! root 214: cpu_state_reset(env); 1.1.1.6 root 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.8 ! root 234: CPUPPCState *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.8 ! root 247: CPUPPCState *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.8 ! root 295: memory_region_init_ram(ram, "mpc8544ds.ram", ram_size); ! 296: vmstate_register_ram_global(ram); 1.1.1.7 root 297: memory_region_add_subregion(address_space_mem, 0, ram); 1.1 root 298: 299: /* MPIC */ 1.1.1.7 root 300: mpic = mpic_init(address_space_mem, MPC8544_MPIC_REGS_BASE, 301: smp_cpus, irqs, NULL); 302: 303: if (!mpic) { 304: cpu_abort(env, "MPIC failed to initialize\n"); 305: } 1.1 root 306: 307: /* Serial */ 1.1.1.4 root 308: if (serial_hds[0]) { 1.1.1.7 root 309: serial_mm_init(address_space_mem, MPC8544_SERIAL0_REGS_BASE, 1.1.1.5 root 310: 0, mpic[12+26], 399193, 1.1.1.7 root 311: serial_hds[0], DEVICE_BIG_ENDIAN); 1.1.1.4 root 312: } 1.1 root 313: 1.1.1.4 root 314: if (serial_hds[1]) { 1.1.1.7 root 315: serial_mm_init(address_space_mem, MPC8544_SERIAL1_REGS_BASE, 1.1.1.5 root 316: 0, mpic[12+26], 399193, 1.1.1.7 root 317: serial_hds[0], DEVICE_BIG_ENDIAN); 1.1.1.4 root 318: } 1.1 root 319: 1.1.1.6 root 320: /* General Utility device */ 321: sysbus_create_simple("mpc8544-guts", MPC8544_UTIL_BASE, NULL); 322: 1.1 root 323: /* PCI */ 1.1.1.6 root 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); 328: pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0"); 1.1 root 329: if (!pci_bus) 330: printf("couldn't create PCI controller!\n"); 331: 1.1.1.5 root 332: isa_mmio_init(MPC8544_PCI_IO, MPC8544_PCI_IOLEN); 1.1 root 333: 334: if (pci_bus) { 335: /* Register network interfaces. */ 336: for (i = 0; i < nb_nics; i++) { 1.1.1.3 root 337: pci_nic_init_nofail(&nd_table[i], "virtio", NULL); 1.1 root 338: } 339: } 340: 1.1.1.7 root 341: /* Register spinning region */ 342: sysbus_create_simple("e500-spin", MPC8544_SPIN_BASE, NULL); 343: 1.1 root 344: /* Load kernel. */ 345: if (kernel_filename) { 346: kernel_size = load_uimage(kernel_filename, &entry, &loadaddr, NULL); 347: if (kernel_size < 0) { 1.1.1.4 root 348: kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry, 349: &elf_lowaddr, NULL, 1, ELF_MACHINE, 0); 1.1 root 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) { 1.1.1.4 root 363: initrd_base = (kernel_size + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK; 1.1.1.2 root 364: initrd_size = load_image_targphys(initrd_filename, initrd_base, 365: ram_size - initrd_base); 1.1 root 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) { 1.1.1.7 root 376: struct boot_info *boot_info; 377: 1.1.1.6 root 378: #ifndef CONFIG_FDT 379: cpu_abort(env, "Compiled without FDT support - can't load kernel\n"); 380: #endif 1.1.1.4 root 381: dt_base = (kernel_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK; 1.1.1.6 root 382: if (mpc8544_load_device_tree(env, dt_base, ram_size, 1.1.1.4 root 383: initrd_base, initrd_size, kernel_cmdline) < 0) { 1.1 root 384: fprintf(stderr, "couldn't load device tree\n"); 385: exit(1); 386: } 387: 1.1.1.7 root 388: boot_info = env->load_info; 1.1.1.6 root 389: boot_info->entry = entry; 390: boot_info->dt_base = dt_base; 1.1 root 391: } 392: 1.1.1.6 root 393: if (kvm_enabled()) { 1.1 root 394: kvmppc_init(); 1.1.1.6 root 395: } 1.1 root 396: } 397: 1.1.1.2 root 398: static QEMUMachine mpc8544ds_machine = { 1.1 root 399: .name = "mpc8544ds", 400: .desc = "mpc8544ds", 401: .init = mpc8544ds_init, 1.1.1.7 root 402: .max_cpus = 15, 1.1 root 403: }; 1.1.1.2 root 404: 405: static void mpc8544ds_machine_init(void) 406: { 407: qemu_register_machine(&mpc8544ds_machine); 408: } 409: 410: machine_init(mpc8544ds_machine_init);
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.