11db09b84Saurel32 /* 2b3305981SScott Wood * QEMU PowerPC e500-based platforms 31db09b84Saurel32 * 41db09b84Saurel32 * Copyright (C) 2009 Freescale Semiconductor, Inc. All rights reserved. 51db09b84Saurel32 * 61db09b84Saurel32 * Author: Yu Liu, <yu.liu@freescale.com> 71db09b84Saurel32 * 81db09b84Saurel32 * This file is derived from hw/ppc440_bamboo.c, 91db09b84Saurel32 * the copyright for that material belongs to the original owners. 101db09b84Saurel32 * 111db09b84Saurel32 * This is free software; you can redistribute it and/or modify 121db09b84Saurel32 * it under the terms of the GNU General Public License as published by 131db09b84Saurel32 * the Free Software Foundation; either version 2 of the License, or 141db09b84Saurel32 * (at your option) any later version. 151db09b84Saurel32 */ 161db09b84Saurel32 171db09b84Saurel32 #include "config.h" 181db09b84Saurel32 #include "qemu-common.h" 19e6eaabebSScott Wood #include "e500.h" 203eddc1beSBharat Bhushan #include "e500-ccsr.h" 211422e32dSPaolo Bonzini #include "net/net.h" 221de7afc9SPaolo Bonzini #include "qemu/config-file.h" 234a18e7c9SScott Wood #include "hw/hw.h" 240d09e41aSPaolo Bonzini #include "hw/char/serial.h" 25a2cb15b0SMichael S. Tsirkin #include "hw/pci/pci.h" 264a18e7c9SScott Wood #include "hw/boards.h" 279c17d615SPaolo Bonzini #include "sysemu/sysemu.h" 289c17d615SPaolo Bonzini #include "sysemu/kvm.h" 291db09b84Saurel32 #include "kvm_ppc.h" 309c17d615SPaolo Bonzini #include "sysemu/device_tree.h" 310d09e41aSPaolo Bonzini #include "hw/ppc/openpic.h" 320d09e41aSPaolo Bonzini #include "hw/ppc/ppc.h" 334a18e7c9SScott Wood #include "hw/loader.h" 34ca20cf32SBlue Swirl #include "elf.h" 354a18e7c9SScott Wood #include "hw/sysbus.h" 36022c62cbSPaolo Bonzini #include "exec/address-spaces.h" 371de7afc9SPaolo Bonzini #include "qemu/host-utils.h" 380d09e41aSPaolo Bonzini #include "hw/pci-host/ppce500.h" 391db09b84Saurel32 40cefd3cdbSBharat Bhushan #define EPAPR_MAGIC (0x45504150) 411db09b84Saurel32 #define BINARY_DEVICE_TREE_FILE "mpc8544ds.dtb" 421db09b84Saurel32 #define UIMAGE_LOAD_BASE 0 439dd5eba1SScott Wood #define DTC_LOAD_PAD 0x1800000 4475bb6589SLiu Yu #define DTC_PAD_MASK 0xFFFFF 45b8dec144SAlexander Graf #define DTB_MAX_SIZE (8 * 1024 * 1024) 4675bb6589SLiu Yu #define INITRD_LOAD_PAD 0x2000000 4775bb6589SLiu Yu #define INITRD_PAD_MASK 0xFFFFFF 481db09b84Saurel32 491db09b84Saurel32 #define RAM_SIZES_ALIGN (64UL << 20) 501db09b84Saurel32 51b3305981SScott Wood /* TODO: parameterize */ 52ed2bc496SAlexander Graf #define MPC8544_CCSRBAR_BASE 0xE0000000ULL 53ed2bc496SAlexander Graf #define MPC8544_CCSRBAR_SIZE 0x00100000ULL 54dffb1dc2SBharat Bhushan #define MPC8544_MPIC_REGS_OFFSET 0x40000ULL 55a911b7a9SAlexander Graf #define MPC8544_MSI_REGS_OFFSET 0x41600ULL 56dffb1dc2SBharat Bhushan #define MPC8544_SERIAL0_REGS_OFFSET 0x4500ULL 57dffb1dc2SBharat Bhushan #define MPC8544_SERIAL1_REGS_OFFSET 0x4600ULL 58dffb1dc2SBharat Bhushan #define MPC8544_PCI_REGS_OFFSET 0x8000ULL 59dffb1dc2SBharat Bhushan #define MPC8544_PCI_REGS_BASE (MPC8544_CCSRBAR_BASE + \ 60dffb1dc2SBharat Bhushan MPC8544_PCI_REGS_OFFSET) 61ed2bc496SAlexander Graf #define MPC8544_PCI_REGS_SIZE 0x1000ULL 62ed2bc496SAlexander Graf #define MPC8544_PCI_IO 0xE1000000ULL 63dffb1dc2SBharat Bhushan #define MPC8544_UTIL_OFFSET 0xe0000ULL 64ed2bc496SAlexander Graf #define MPC8544_SPIN_BASE 0xEF000000ULL 651db09b84Saurel32 663b989d49SAlexander Graf struct boot_info 673b989d49SAlexander Graf { 683b989d49SAlexander Graf uint32_t dt_base; 69cba2026aSAlexander Graf uint32_t dt_size; 703b989d49SAlexander Graf uint32_t entry; 713b989d49SAlexander Graf }; 723b989d49SAlexander Graf 73347dd79dSAlexander Graf static uint32_t *pci_map_create(void *fdt, uint32_t mpic, int first_slot, 74347dd79dSAlexander Graf int nr_slots, int *len) 750dbc0798SAlexander Graf { 76347dd79dSAlexander Graf int i = 0; 77347dd79dSAlexander Graf int slot; 78347dd79dSAlexander Graf int pci_irq; 799e2c1298SAlexander Graf int host_irq; 80347dd79dSAlexander Graf int last_slot = first_slot + nr_slots; 81347dd79dSAlexander Graf uint32_t *pci_map; 820dbc0798SAlexander Graf 83347dd79dSAlexander Graf *len = nr_slots * 4 * 7 * sizeof(uint32_t); 84347dd79dSAlexander Graf pci_map = g_malloc(*len); 85347dd79dSAlexander Graf 86347dd79dSAlexander Graf for (slot = first_slot; slot < last_slot; slot++) { 87347dd79dSAlexander Graf for (pci_irq = 0; pci_irq < 4; pci_irq++) { 88347dd79dSAlexander Graf pci_map[i++] = cpu_to_be32(slot << 11); 89347dd79dSAlexander Graf pci_map[i++] = cpu_to_be32(0x0); 90347dd79dSAlexander Graf pci_map[i++] = cpu_to_be32(0x0); 91347dd79dSAlexander Graf pci_map[i++] = cpu_to_be32(pci_irq + 1); 92347dd79dSAlexander Graf pci_map[i++] = cpu_to_be32(mpic); 939e2c1298SAlexander Graf host_irq = ppce500_pci_map_irq_slot(slot, pci_irq); 949e2c1298SAlexander Graf pci_map[i++] = cpu_to_be32(host_irq + 1); 95347dd79dSAlexander Graf pci_map[i++] = cpu_to_be32(0x1); 960dbc0798SAlexander Graf } 970dbc0798SAlexander Graf } 980dbc0798SAlexander Graf 99347dd79dSAlexander Graf assert((i * sizeof(uint32_t)) == *len); 100347dd79dSAlexander Graf 101347dd79dSAlexander Graf return pci_map; 102347dd79dSAlexander Graf } 103347dd79dSAlexander Graf 104a053a7ceSAlexander Graf static void dt_serial_create(void *fdt, unsigned long long offset, 105a053a7ceSAlexander Graf const char *soc, const char *mpic, 106a053a7ceSAlexander Graf const char *alias, int idx, bool defcon) 107a053a7ceSAlexander Graf { 108a053a7ceSAlexander Graf char ser[128]; 109a053a7ceSAlexander Graf 110a053a7ceSAlexander Graf snprintf(ser, sizeof(ser), "%s/serial@%llx", soc, offset); 1115a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, ser); 1125a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, ser, "device_type", "serial"); 1135a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, ser, "compatible", "ns16550"); 1145a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, ser, "reg", offset, 0x100); 1155a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, ser, "cell-index", idx); 1165a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, ser, "clock-frequency", 0); 1175a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, ser, "interrupts", 42, 2); 1185a4348d1SPeter Crosthwaite qemu_fdt_setprop_phandle(fdt, ser, "interrupt-parent", mpic); 1195a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, "/aliases", alias, ser); 120a053a7ceSAlexander Graf 121a053a7ceSAlexander Graf if (defcon) { 1225a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, "/chosen", "linux,stdout-path", ser); 123a053a7ceSAlexander Graf } 124a053a7ceSAlexander Graf } 125a053a7ceSAlexander Graf 12628290f37SAlexander Graf static int ppce500_load_device_tree(QEMUMachineInitArgs *args, 127e6eaabebSScott Wood PPCE500Params *params, 128a8170e5eSAvi Kivity hwaddr addr, 129a8170e5eSAvi Kivity hwaddr initrd_base, 13028290f37SAlexander Graf hwaddr initrd_size, 13128290f37SAlexander Graf bool dry_run) 1321db09b84Saurel32 { 13328290f37SAlexander Graf CPUPPCState *env = first_cpu->env_ptr; 134dbf916d8SAurelien Jarno int ret = -1; 13592238367SMarkus Armbruster uint64_t mem_reg_property[] = { 0, cpu_to_be64(args->ram_size) }; 1367ec632b4Spbrook int fdt_size; 137dbf916d8SAurelien Jarno void *fdt; 1385de6b46dSAlexander Graf uint8_t hypercall[16]; 139911d6e7aSAlexander Graf uint32_t clock_freq = 400000000; 140911d6e7aSAlexander Graf uint32_t tb_freq = 400000000; 141621d05e3SAlexander Graf int i; 142ebb9518aSAlexander Graf char compatible_sb[] = "fsl,mpc8544-immr\0simple-bus"; 1435da96624SAlexander Graf char soc[128]; 14419ac9deaSAlexander Graf char mpic[128]; 14519ac9deaSAlexander Graf uint32_t mpic_ph; 146a911b7a9SAlexander Graf uint32_t msi_ph; 147f5038483SAlexander Graf char gutil[128]; 1480dbc0798SAlexander Graf char pci[128]; 149a911b7a9SAlexander Graf char msi[128]; 150347dd79dSAlexander Graf uint32_t *pci_map = NULL; 151347dd79dSAlexander Graf int len; 1523627757eSAlexander Graf uint32_t pci_ranges[14] = 1533627757eSAlexander Graf { 1543627757eSAlexander Graf 0x2000000, 0x0, 0xc0000000, 1553627757eSAlexander Graf 0x0, 0xc0000000, 1563627757eSAlexander Graf 0x0, 0x20000000, 1573627757eSAlexander Graf 1583627757eSAlexander Graf 0x1000000, 0x0, 0x0, 1593627757eSAlexander Graf 0x0, 0xe1000000, 1603627757eSAlexander Graf 0x0, 0x10000, 1613627757eSAlexander Graf }; 1622ff3de68SMarkus Armbruster QemuOpts *machine_opts = qemu_get_machine_opts(); 1632ff3de68SMarkus Armbruster const char *dtb_file = qemu_opt_get(machine_opts, "dtb"); 1642ff3de68SMarkus Armbruster const char *toplevel_compat = qemu_opt_get(machine_opts, "dt_compatible"); 165d1b93565SAlexander Graf 166d1b93565SAlexander Graf if (dtb_file) { 167d1b93565SAlexander Graf char *filename; 168d1b93565SAlexander Graf filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_file); 169d1b93565SAlexander Graf if (!filename) { 170d1b93565SAlexander Graf goto out; 171d1b93565SAlexander Graf } 172d1b93565SAlexander Graf 173d1b93565SAlexander Graf fdt = load_device_tree(filename, &fdt_size); 174d1b93565SAlexander Graf if (!fdt) { 175d1b93565SAlexander Graf goto out; 176d1b93565SAlexander Graf } 177d1b93565SAlexander Graf goto done; 178d1b93565SAlexander Graf } 1791db09b84Saurel32 1802636fcb6SAlexander Graf fdt = create_device_tree(&fdt_size); 1815cea8590SPaul Brook if (fdt == NULL) { 1825cea8590SPaul Brook goto out; 1835cea8590SPaul Brook } 1841db09b84Saurel32 1851db09b84Saurel32 /* Manipulate device tree in memory. */ 1865a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 2); 1875a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 2); 18851b852b7SAlexander Graf 1895a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, "/memory"); 1905a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, "/memory", "device_type", "memory"); 1915a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, "/memory", "reg", mem_reg_property, 1921db09b84Saurel32 sizeof(mem_reg_property)); 1931db09b84Saurel32 1945a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, "/chosen"); 1953b989d49SAlexander Graf if (initrd_size) { 1965a4348d1SPeter Crosthwaite ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start", 1971db09b84Saurel32 initrd_base); 1983b989d49SAlexander Graf if (ret < 0) { 1991db09b84Saurel32 fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n"); 2003b989d49SAlexander Graf } 2011db09b84Saurel32 2025a4348d1SPeter Crosthwaite ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end", 2031db09b84Saurel32 (initrd_base + initrd_size)); 2043b989d49SAlexander Graf if (ret < 0) { 2051db09b84Saurel32 fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n"); 2063b989d49SAlexander Graf } 2073b989d49SAlexander Graf } 2081db09b84Saurel32 2095a4348d1SPeter Crosthwaite ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", 21092238367SMarkus Armbruster args->kernel_cmdline); 2111db09b84Saurel32 if (ret < 0) 2121db09b84Saurel32 fprintf(stderr, "couldn't set /chosen/bootargs\n"); 2131db09b84Saurel32 2141db09b84Saurel32 if (kvm_enabled()) { 215911d6e7aSAlexander Graf /* Read out host's frequencies */ 216911d6e7aSAlexander Graf clock_freq = kvmppc_get_clockfreq(); 217911d6e7aSAlexander Graf tb_freq = kvmppc_get_tbfreq(); 2185de6b46dSAlexander Graf 2195de6b46dSAlexander Graf /* indicate KVM hypercall interface */ 2205a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, "/hypervisor"); 2215a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, "/hypervisor", "compatible", 2225de6b46dSAlexander Graf "linux,kvm"); 2235de6b46dSAlexander Graf kvmppc_get_hypercall(env, hypercall, sizeof(hypercall)); 2245a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, "/hypervisor", "hcall-instructions", 2255de6b46dSAlexander Graf hypercall, sizeof(hypercall)); 2261a61a9aeSStuart Yoder /* if KVM supports the idle hcall, set property indicating this */ 2271a61a9aeSStuart Yoder if (kvmppc_get_hasidle(env)) { 2285a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, "/hypervisor", "has-idle", NULL, 0); 2291a61a9aeSStuart Yoder } 2301db09b84Saurel32 } 2311db09b84Saurel32 232625e665bSAlexander Graf /* Create CPU nodes */ 2335a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, "/cpus"); 2345a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 1); 2355a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0); 236625e665bSAlexander Graf 2371e3debf0SAlexander Graf /* We need to generate the cpu nodes in reverse order, so Linux can pick 2381e3debf0SAlexander Graf the first node as boot node and be happy */ 2391e3debf0SAlexander Graf for (i = smp_cpus - 1; i >= 0; i--) { 240440c8152SAndreas Färber CPUState *cpu; 241*0f20ba62SAlexey Kardashevskiy PowerPCCPU *pcpu; 242621d05e3SAlexander Graf char cpu_name[128]; 2431d2e5c52SAlexander Graf uint64_t cpu_release_addr = MPC8544_SPIN_BASE + (i * 0x20); 24410f25a46SAlexander Graf 245440c8152SAndreas Färber cpu = qemu_get_cpu(i); 24655e5c285SAndreas Färber if (cpu == NULL) { 2471e3debf0SAlexander Graf continue; 2481e3debf0SAlexander Graf } 249440c8152SAndreas Färber env = cpu->env_ptr; 250*0f20ba62SAlexey Kardashevskiy pcpu = POWERPC_CPU(cpu); 2511e3debf0SAlexander Graf 25255e5c285SAndreas Färber snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x", 253*0f20ba62SAlexey Kardashevskiy ppc_get_vcpu_dt_id(pcpu)); 2545a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, cpu_name); 2555a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq); 2565a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq); 2575a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, cpu_name, "device_type", "cpu"); 258*0f20ba62SAlexey Kardashevskiy qemu_fdt_setprop_cell(fdt, cpu_name, "reg", 259*0f20ba62SAlexey Kardashevskiy ppc_get_vcpu_dt_id(pcpu)); 2605a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-line-size", 2611e3debf0SAlexander Graf env->dcache_line_size); 2625a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-line-size", 2631e3debf0SAlexander Graf env->icache_line_size); 2645a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-size", 0x8000); 2655a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-size", 0x8000); 2665a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "bus-frequency", 0); 26755e5c285SAndreas Färber if (cpu->cpu_index) { 2685a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, cpu_name, "status", "disabled"); 2695a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, cpu_name, "enable-method", 2705a4348d1SPeter Crosthwaite "spin-table"); 2715a4348d1SPeter Crosthwaite qemu_fdt_setprop_u64(fdt, cpu_name, "cpu-release-addr", 2721d2e5c52SAlexander Graf cpu_release_addr); 2731e3debf0SAlexander Graf } else { 2745a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, cpu_name, "status", "okay"); 2751e3debf0SAlexander Graf } 2761db09b84Saurel32 } 2771db09b84Saurel32 2785a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, "/aliases"); 2795da96624SAlexander Graf /* XXX These should go into their respective devices' code */ 280ed2bc496SAlexander Graf snprintf(soc, sizeof(soc), "/soc@%llx", MPC8544_CCSRBAR_BASE); 2815a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, soc); 2825a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, soc, "device_type", "soc"); 2835a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, soc, "compatible", compatible_sb, 284ebb9518aSAlexander Graf sizeof(compatible_sb)); 2855a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, soc, "#address-cells", 1); 2865a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, soc, "#size-cells", 1); 2875a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, soc, "ranges", 0x0, 2883627757eSAlexander Graf MPC8544_CCSRBAR_BASE >> 32, MPC8544_CCSRBAR_BASE, 2895da96624SAlexander Graf MPC8544_CCSRBAR_SIZE); 2905da96624SAlexander Graf /* XXX should contain a reasonable value */ 2915a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, soc, "bus-frequency", 0); 2925da96624SAlexander Graf 293dffb1dc2SBharat Bhushan snprintf(mpic, sizeof(mpic), "%s/pic@%llx", soc, MPC8544_MPIC_REGS_OFFSET); 2945a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, mpic); 2955a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, mpic, "device_type", "open-pic"); 2965a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, mpic, "compatible", "fsl,mpic"); 2975a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_OFFSET, 298dffb1dc2SBharat Bhushan 0x40000); 2995a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, mpic, "#address-cells", 0); 3005a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, mpic, "#interrupt-cells", 2); 3015a4348d1SPeter Crosthwaite mpic_ph = qemu_fdt_alloc_phandle(fdt); 3025a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, mpic, "phandle", mpic_ph); 3035a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, mpic, "linux,phandle", mpic_ph); 3045a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, mpic, "interrupt-controller", NULL, 0); 30519ac9deaSAlexander Graf 3060cfc6e8dSAlexander Graf /* 3070cfc6e8dSAlexander Graf * We have to generate ser1 first, because Linux takes the first 3080cfc6e8dSAlexander Graf * device it finds in the dt as serial output device. And we generate 3090cfc6e8dSAlexander Graf * devices in reverse order to the dt. 3100cfc6e8dSAlexander Graf */ 311dffb1dc2SBharat Bhushan dt_serial_create(fdt, MPC8544_SERIAL1_REGS_OFFSET, 312a053a7ceSAlexander Graf soc, mpic, "serial1", 1, false); 313dffb1dc2SBharat Bhushan dt_serial_create(fdt, MPC8544_SERIAL0_REGS_OFFSET, 314a053a7ceSAlexander Graf soc, mpic, "serial0", 0, true); 3150cfc6e8dSAlexander Graf 316ed2bc496SAlexander Graf snprintf(gutil, sizeof(gutil), "%s/global-utilities@%llx", soc, 317dffb1dc2SBharat Bhushan MPC8544_UTIL_OFFSET); 3185a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, gutil); 3195a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, gutil, "compatible", "fsl,mpc8544-guts"); 3205a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, gutil, "reg", MPC8544_UTIL_OFFSET, 0x1000); 3215a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, gutil, "fsl,has-rstcr", NULL, 0); 322f5038483SAlexander Graf 323a911b7a9SAlexander Graf snprintf(msi, sizeof(msi), "/%s/msi@%llx", soc, MPC8544_MSI_REGS_OFFSET); 3245a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, msi); 3255a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, msi, "compatible", "fsl,mpic-msi"); 3265a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, msi, "reg", MPC8544_MSI_REGS_OFFSET, 0x200); 3275a4348d1SPeter Crosthwaite msi_ph = qemu_fdt_alloc_phandle(fdt); 3285a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, msi, "msi-available-ranges", 0x0, 0x100); 3295a4348d1SPeter Crosthwaite qemu_fdt_setprop_phandle(fdt, msi, "interrupt-parent", mpic); 3305a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, msi, "interrupts", 331a911b7a9SAlexander Graf 0xe0, 0x0, 332a911b7a9SAlexander Graf 0xe1, 0x0, 333a911b7a9SAlexander Graf 0xe2, 0x0, 334a911b7a9SAlexander Graf 0xe3, 0x0, 335a911b7a9SAlexander Graf 0xe4, 0x0, 336a911b7a9SAlexander Graf 0xe5, 0x0, 337a911b7a9SAlexander Graf 0xe6, 0x0, 338a911b7a9SAlexander Graf 0xe7, 0x0); 3395a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, msi, "phandle", msi_ph); 3405a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, msi, "linux,phandle", msi_ph); 341a911b7a9SAlexander Graf 342ed2bc496SAlexander Graf snprintf(pci, sizeof(pci), "/pci@%llx", MPC8544_PCI_REGS_BASE); 3435a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, pci); 3445a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, pci, "cell-index", 0); 3455a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, pci, "compatible", "fsl,mpc8540-pci"); 3465a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, pci, "device_type", "pci"); 3475a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, pci, "interrupt-map-mask", 0xf800, 0x0, 3480dbc0798SAlexander Graf 0x0, 0x7); 3495a4348d1SPeter Crosthwaite pci_map = pci_map_create(fdt, qemu_fdt_get_phandle(fdt, mpic), 350492ec48dSAlexander Graf params->pci_first_slot, params->pci_nr_slots, 351492ec48dSAlexander Graf &len); 3525a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, pci, "interrupt-map", pci_map, len); 3535a4348d1SPeter Crosthwaite qemu_fdt_setprop_phandle(fdt, pci, "interrupt-parent", mpic); 3545a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, pci, "interrupts", 24, 2); 3555a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, pci, "bus-range", 0, 255); 3563627757eSAlexander Graf for (i = 0; i < 14; i++) { 3570dbc0798SAlexander Graf pci_ranges[i] = cpu_to_be32(pci_ranges[i]); 3580dbc0798SAlexander Graf } 3595a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, pci, "fsl,msi", msi_ph); 3605a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, pci, "ranges", pci_ranges, sizeof(pci_ranges)); 3615a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, pci, "reg", MPC8544_PCI_REGS_BASE >> 32, 3623627757eSAlexander Graf MPC8544_PCI_REGS_BASE, 0, 0x1000); 3635a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, pci, "clock-frequency", 66666666); 3645a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, pci, "#interrupt-cells", 1); 3655a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, pci, "#size-cells", 2); 3665a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, pci, "#address-cells", 3); 3675a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, "/aliases", "pci0", pci); 3680dbc0798SAlexander Graf 369e6eaabebSScott Wood params->fixup_devtree(params, fdt); 370e6eaabebSScott Wood 371e6eaabebSScott Wood if (toplevel_compat) { 3725a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, "/", "compatible", toplevel_compat, 373e6eaabebSScott Wood strlen(toplevel_compat) + 1); 374e6eaabebSScott Wood } 375e6eaabebSScott Wood 376d1b93565SAlexander Graf done: 37728290f37SAlexander Graf if (!dry_run) { 3785a4348d1SPeter Crosthwaite qemu_fdt_dumpdtb(fdt, fdt_size); 37928290f37SAlexander Graf cpu_physical_memory_write(addr, fdt, fdt_size); 380cba2026aSAlexander Graf } 381cba2026aSAlexander Graf ret = fdt_size; 3827ec632b4Spbrook 3831db09b84Saurel32 out: 384347dd79dSAlexander Graf g_free(pci_map); 3851db09b84Saurel32 38604088adbSLiu Yu return ret; 3871db09b84Saurel32 } 3881db09b84Saurel32 38928290f37SAlexander Graf typedef struct DeviceTreeParams { 39028290f37SAlexander Graf QEMUMachineInitArgs args; 39128290f37SAlexander Graf PPCE500Params params; 39228290f37SAlexander Graf hwaddr addr; 39328290f37SAlexander Graf hwaddr initrd_base; 39428290f37SAlexander Graf hwaddr initrd_size; 39528290f37SAlexander Graf } DeviceTreeParams; 39628290f37SAlexander Graf 39728290f37SAlexander Graf static void ppce500_reset_device_tree(void *opaque) 39828290f37SAlexander Graf { 39928290f37SAlexander Graf DeviceTreeParams *p = opaque; 40028290f37SAlexander Graf ppce500_load_device_tree(&p->args, &p->params, p->addr, p->initrd_base, 40128290f37SAlexander Graf p->initrd_size, false); 40228290f37SAlexander Graf } 40328290f37SAlexander Graf 40428290f37SAlexander Graf static int ppce500_prep_device_tree(QEMUMachineInitArgs *args, 40528290f37SAlexander Graf PPCE500Params *params, 40628290f37SAlexander Graf hwaddr addr, 40728290f37SAlexander Graf hwaddr initrd_base, 40828290f37SAlexander Graf hwaddr initrd_size) 40928290f37SAlexander Graf { 41028290f37SAlexander Graf DeviceTreeParams *p = g_new(DeviceTreeParams, 1); 41128290f37SAlexander Graf p->args = *args; 41228290f37SAlexander Graf p->params = *params; 41328290f37SAlexander Graf p->addr = addr; 41428290f37SAlexander Graf p->initrd_base = initrd_base; 41528290f37SAlexander Graf p->initrd_size = initrd_size; 41628290f37SAlexander Graf 41728290f37SAlexander Graf qemu_register_reset(ppce500_reset_device_tree, p); 41828290f37SAlexander Graf 41928290f37SAlexander Graf /* Issue the device tree loader once, so that we get the size of the blob */ 42028290f37SAlexander Graf return ppce500_load_device_tree(args, params, addr, initrd_base, 42128290f37SAlexander Graf initrd_size, true); 42228290f37SAlexander Graf } 42328290f37SAlexander Graf 424cba2026aSAlexander Graf /* Create -kernel TLB entries for BookE. */ 425a8170e5eSAvi Kivity static inline hwaddr booke206_page_size_to_tlb(uint64_t size) 426d1e256feSAlexander Graf { 427cba2026aSAlexander Graf return 63 - clz64(size >> 10); 428d1e256feSAlexander Graf } 429d1e256feSAlexander Graf 430cefd3cdbSBharat Bhushan static int booke206_initial_map_tsize(CPUPPCState *env) 4313b989d49SAlexander Graf { 432cba2026aSAlexander Graf struct boot_info *bi = env->load_info; 433cefd3cdbSBharat Bhushan hwaddr dt_end; 434cba2026aSAlexander Graf int ps; 4353b989d49SAlexander Graf 436cba2026aSAlexander Graf /* Our initial TLB entry needs to cover everything from 0 to 437cba2026aSAlexander Graf the device tree top */ 438cba2026aSAlexander Graf dt_end = bi->dt_base + bi->dt_size; 439cba2026aSAlexander Graf ps = booke206_page_size_to_tlb(dt_end) + 1; 440fb37c302SAlexander Graf if (ps & 1) { 441fb37c302SAlexander Graf /* e500v2 can only do even TLB size bits */ 442fb37c302SAlexander Graf ps++; 443fb37c302SAlexander Graf } 444cefd3cdbSBharat Bhushan return ps; 445cefd3cdbSBharat Bhushan } 446cefd3cdbSBharat Bhushan 447cefd3cdbSBharat Bhushan static uint64_t mmubooke_initial_mapsize(CPUPPCState *env) 448cefd3cdbSBharat Bhushan { 449cefd3cdbSBharat Bhushan int tsize; 450cefd3cdbSBharat Bhushan 451cefd3cdbSBharat Bhushan tsize = booke206_initial_map_tsize(env); 452cefd3cdbSBharat Bhushan return (1ULL << 10 << tsize); 453cefd3cdbSBharat Bhushan } 454cefd3cdbSBharat Bhushan 455cefd3cdbSBharat Bhushan static void mmubooke_create_initial_mapping(CPUPPCState *env) 456cefd3cdbSBharat Bhushan { 457cefd3cdbSBharat Bhushan ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0); 458cefd3cdbSBharat Bhushan hwaddr size; 459cefd3cdbSBharat Bhushan int ps; 460cefd3cdbSBharat Bhushan 461cefd3cdbSBharat Bhushan ps = booke206_initial_map_tsize(env); 462cba2026aSAlexander Graf size = (ps << MAS1_TSIZE_SHIFT); 463d1e256feSAlexander Graf tlb->mas1 = MAS1_VALID | size; 464cba2026aSAlexander Graf tlb->mas2 = 0; 465cba2026aSAlexander Graf tlb->mas7_3 = 0; 466d1e256feSAlexander Graf tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX; 46793dd5e85SScott Wood 46893dd5e85SScott Wood env->tlb_dirty = true; 4693b989d49SAlexander Graf } 4703b989d49SAlexander Graf 471b3305981SScott Wood static void ppce500_cpu_reset_sec(void *opaque) 4725c145dacSAlexander Graf { 47338f92da6SAndreas Färber PowerPCCPU *cpu = opaque; 474259186a7SAndreas Färber CPUState *cs = CPU(cpu); 47538f92da6SAndreas Färber CPUPPCState *env = &cpu->env; 4765c145dacSAlexander Graf 477259186a7SAndreas Färber cpu_reset(cs); 4785c145dacSAlexander Graf 4795c145dacSAlexander Graf /* Secondary CPU starts in halted state for now. Needs to change when 4805c145dacSAlexander Graf implementing non-kernel boot. */ 481259186a7SAndreas Färber cs->halted = 1; 4825c145dacSAlexander Graf env->exception_index = EXCP_HLT; 4833b989d49SAlexander Graf } 4843b989d49SAlexander Graf 485b3305981SScott Wood static void ppce500_cpu_reset(void *opaque) 4863b989d49SAlexander Graf { 48738f92da6SAndreas Färber PowerPCCPU *cpu = opaque; 488259186a7SAndreas Färber CPUState *cs = CPU(cpu); 48938f92da6SAndreas Färber CPUPPCState *env = &cpu->env; 4903b989d49SAlexander Graf struct boot_info *bi = env->load_info; 4913b989d49SAlexander Graf 492259186a7SAndreas Färber cpu_reset(cs); 4933b989d49SAlexander Graf 4943b989d49SAlexander Graf /* Set initial guest state. */ 495259186a7SAndreas Färber cs->halted = 0; 4963b989d49SAlexander Graf env->gpr[1] = (16<<20) - 8; 4973b989d49SAlexander Graf env->gpr[3] = bi->dt_base; 498cefd3cdbSBharat Bhushan env->gpr[4] = 0; 499cefd3cdbSBharat Bhushan env->gpr[5] = 0; 500cefd3cdbSBharat Bhushan env->gpr[6] = EPAPR_MAGIC; 501cefd3cdbSBharat Bhushan env->gpr[7] = mmubooke_initial_mapsize(env); 502cefd3cdbSBharat Bhushan env->gpr[8] = 0; 503cefd3cdbSBharat Bhushan env->gpr[9] = 0; 5043b989d49SAlexander Graf env->nip = bi->entry; 505cba2026aSAlexander Graf mmubooke_create_initial_mapping(env); 5063b989d49SAlexander Graf } 5073b989d49SAlexander Graf 508d85937e6SScott Wood static DeviceState *ppce500_init_mpic_qemu(PPCE500Params *params, 50982fc73b6SScott Wood qemu_irq **irqs) 51082fc73b6SScott Wood { 51182fc73b6SScott Wood DeviceState *dev; 51282fc73b6SScott Wood SysBusDevice *s; 51382fc73b6SScott Wood int i, j, k; 51482fc73b6SScott Wood 515e1766344SAndreas Färber dev = qdev_create(NULL, TYPE_OPENPIC); 51682fc73b6SScott Wood qdev_prop_set_uint32(dev, "model", params->mpic_version); 517d85937e6SScott Wood qdev_prop_set_uint32(dev, "nb_cpus", smp_cpus); 518d85937e6SScott Wood 51982fc73b6SScott Wood qdev_init_nofail(dev); 52082fc73b6SScott Wood s = SYS_BUS_DEVICE(dev); 52182fc73b6SScott Wood 52282fc73b6SScott Wood k = 0; 52382fc73b6SScott Wood for (i = 0; i < smp_cpus; i++) { 52482fc73b6SScott Wood for (j = 0; j < OPENPIC_OUTPUT_NB; j++) { 52582fc73b6SScott Wood sysbus_connect_irq(s, k++, irqs[i][j]); 52682fc73b6SScott Wood } 52782fc73b6SScott Wood } 52882fc73b6SScott Wood 529d85937e6SScott Wood return dev; 530d85937e6SScott Wood } 531d85937e6SScott Wood 532d85937e6SScott Wood static DeviceState *ppce500_init_mpic_kvm(PPCE500Params *params, 533d85937e6SScott Wood qemu_irq **irqs) 534d85937e6SScott Wood { 535d85937e6SScott Wood DeviceState *dev; 536d85937e6SScott Wood CPUState *cs; 537d85937e6SScott Wood int r; 538d85937e6SScott Wood 539dd49c038SAndreas Färber dev = qdev_create(NULL, TYPE_KVM_OPENPIC); 540d85937e6SScott Wood qdev_prop_set_uint32(dev, "model", params->mpic_version); 541d85937e6SScott Wood 542d85937e6SScott Wood r = qdev_init(dev); 543d85937e6SScott Wood if (r) { 544d85937e6SScott Wood return NULL; 545d85937e6SScott Wood } 546d85937e6SScott Wood 547bdc44640SAndreas Färber CPU_FOREACH(cs) { 548d85937e6SScott Wood if (kvm_openpic_connect_vcpu(dev, cs)) { 549d85937e6SScott Wood fprintf(stderr, "%s: failed to connect vcpu to irqchip\n", 550d85937e6SScott Wood __func__); 551d85937e6SScott Wood abort(); 552d85937e6SScott Wood } 553d85937e6SScott Wood } 554d85937e6SScott Wood 555d85937e6SScott Wood return dev; 556d85937e6SScott Wood } 557d85937e6SScott Wood 558d85937e6SScott Wood static qemu_irq *ppce500_init_mpic(PPCE500Params *params, MemoryRegion *ccsr, 559d85937e6SScott Wood qemu_irq **irqs) 560d85937e6SScott Wood { 561d85937e6SScott Wood qemu_irq *mpic; 562d85937e6SScott Wood DeviceState *dev = NULL; 563d85937e6SScott Wood SysBusDevice *s; 564d85937e6SScott Wood int i; 565d85937e6SScott Wood 566d85937e6SScott Wood mpic = g_new(qemu_irq, 256); 567d85937e6SScott Wood 568d85937e6SScott Wood if (kvm_enabled()) { 56936ad0e94SMarkus Armbruster QemuOpts *machine_opts = qemu_get_machine_opts(); 57036ad0e94SMarkus Armbruster bool irqchip_allowed = qemu_opt_get_bool(machine_opts, 571d85937e6SScott Wood "kernel_irqchip", true); 57236ad0e94SMarkus Armbruster bool irqchip_required = qemu_opt_get_bool(machine_opts, 573d85937e6SScott Wood "kernel_irqchip", false); 574d85937e6SScott Wood 575d85937e6SScott Wood if (irqchip_allowed) { 576d85937e6SScott Wood dev = ppce500_init_mpic_kvm(params, irqs); 577d85937e6SScott Wood } 578d85937e6SScott Wood 579d85937e6SScott Wood if (irqchip_required && !dev) { 580d85937e6SScott Wood fprintf(stderr, "%s: irqchip requested but unavailable\n", 581d85937e6SScott Wood __func__); 582d85937e6SScott Wood abort(); 583d85937e6SScott Wood } 584d85937e6SScott Wood } 585d85937e6SScott Wood 586d85937e6SScott Wood if (!dev) { 587d85937e6SScott Wood dev = ppce500_init_mpic_qemu(params, irqs); 588d85937e6SScott Wood } 589d85937e6SScott Wood 59082fc73b6SScott Wood for (i = 0; i < 256; i++) { 59182fc73b6SScott Wood mpic[i] = qdev_get_gpio_in(dev, i); 59282fc73b6SScott Wood } 59382fc73b6SScott Wood 594d85937e6SScott Wood s = SYS_BUS_DEVICE(dev); 59582fc73b6SScott Wood memory_region_add_subregion(ccsr, MPC8544_MPIC_REGS_OFFSET, 59682fc73b6SScott Wood s->mmio[0].memory); 59782fc73b6SScott Wood 59882fc73b6SScott Wood return mpic; 59982fc73b6SScott Wood } 60082fc73b6SScott Wood 60192238367SMarkus Armbruster void ppce500_init(QEMUMachineInitArgs *args, PPCE500Params *params) 6021db09b84Saurel32 { 60339186d8aSRichard Henderson MemoryRegion *address_space_mem = get_system_memory(); 6042646c133SAvi Kivity MemoryRegion *ram = g_new(MemoryRegion, 1); 6051db09b84Saurel32 PCIBus *pci_bus; 606e2684c0bSAndreas Färber CPUPPCState *env = NULL; 6071db09b84Saurel32 uint64_t elf_entry; 6081db09b84Saurel32 uint64_t elf_lowaddr; 609a8170e5eSAvi Kivity hwaddr entry=0; 610a8170e5eSAvi Kivity hwaddr loadaddr=UIMAGE_LOAD_BASE; 6111db09b84Saurel32 target_long kernel_size=0; 61275bb6589SLiu Yu target_ulong dt_base = 0; 61375bb6589SLiu Yu target_ulong initrd_base = 0; 6141db09b84Saurel32 target_long initrd_size = 0; 615528e536eSAlexander Graf target_ulong cur_base = 0; 61682fc73b6SScott Wood int i; 6171db09b84Saurel32 unsigned int pci_irq_nrs[4] = {1, 2, 3, 4}; 618a915249fSAlexander Graf qemu_irq **irqs, *mpic; 619be13cc7aSAlexander Graf DeviceState *dev; 620e2684c0bSAndreas Färber CPUPPCState *firstenv = NULL; 6213eddc1beSBharat Bhushan MemoryRegion *ccsr_addr_space; 622dffb1dc2SBharat Bhushan SysBusDevice *s; 6233eddc1beSBharat Bhushan PPCE500CCSRState *ccsr; 6241db09b84Saurel32 625e61c36d5SAlexander Graf /* Setup CPUs */ 62692238367SMarkus Armbruster if (args->cpu_model == NULL) { 62792238367SMarkus Armbruster args->cpu_model = "e500v2_v30"; 628ef250db6SAlexander Graf } 629ef250db6SAlexander Graf 630a915249fSAlexander Graf irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *)); 631a915249fSAlexander Graf irqs[0] = g_malloc0(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB); 632e61c36d5SAlexander Graf for (i = 0; i < smp_cpus; i++) { 633397b457dSAndreas Färber PowerPCCPU *cpu; 63455e5c285SAndreas Färber CPUState *cs; 635e61c36d5SAlexander Graf qemu_irq *input; 636397b457dSAndreas Färber 63792238367SMarkus Armbruster cpu = cpu_ppc_init(args->cpu_model); 638397b457dSAndreas Färber if (cpu == NULL) { 6391db09b84Saurel32 fprintf(stderr, "Unable to initialize CPU!\n"); 6401db09b84Saurel32 exit(1); 6411db09b84Saurel32 } 642397b457dSAndreas Färber env = &cpu->env; 64355e5c285SAndreas Färber cs = CPU(cpu); 6441db09b84Saurel32 645e61c36d5SAlexander Graf if (!firstenv) { 646e61c36d5SAlexander Graf firstenv = env; 647e61c36d5SAlexander Graf } 648e61c36d5SAlexander Graf 649a915249fSAlexander Graf irqs[i] = irqs[0] + (i * OPENPIC_OUTPUT_NB); 650a915249fSAlexander Graf input = (qemu_irq *)env->irq_inputs; 651a915249fSAlexander Graf irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT]; 652a915249fSAlexander Graf irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT]; 65355e5c285SAndreas Färber env->spr[SPR_BOOKE_PIR] = cs->cpu_index = i; 65468c2dd70SAlexander Graf env->mpic_iack = MPC8544_CCSRBAR_BASE + 655bd25922eSScott Wood MPC8544_MPIC_REGS_OFFSET + 0xa0; 656e61c36d5SAlexander Graf 657a34a92b9SAndreas Färber ppc_booke_timers_init(cpu, 400000000, PPC_TIMER_E500); 6583b989d49SAlexander Graf 6593b989d49SAlexander Graf /* Register reset handler */ 6605c145dacSAlexander Graf if (!i) { 6615c145dacSAlexander Graf /* Primary CPU */ 6625c145dacSAlexander Graf struct boot_info *boot_info; 663e61c36d5SAlexander Graf boot_info = g_malloc0(sizeof(struct boot_info)); 664b3305981SScott Wood qemu_register_reset(ppce500_cpu_reset, cpu); 665e61c36d5SAlexander Graf env->load_info = boot_info; 6665c145dacSAlexander Graf } else { 6675c145dacSAlexander Graf /* Secondary CPUs */ 668b3305981SScott Wood qemu_register_reset(ppce500_cpu_reset_sec, cpu); 6695c145dacSAlexander Graf } 670e61c36d5SAlexander Graf } 671e61c36d5SAlexander Graf 672e61c36d5SAlexander Graf env = firstenv; 6733b989d49SAlexander Graf 6741db09b84Saurel32 /* Fixup Memory size on a alignment boundary */ 6751db09b84Saurel32 ram_size &= ~(RAM_SIZES_ALIGN - 1); 67692238367SMarkus Armbruster args->ram_size = ram_size; 6771db09b84Saurel32 6781db09b84Saurel32 /* Register Memory */ 6792c9b15caSPaolo Bonzini memory_region_init_ram(ram, NULL, "mpc8544ds.ram", ram_size); 680c5705a77SAvi Kivity vmstate_register_ram_global(ram); 6812646c133SAvi Kivity memory_region_add_subregion(address_space_mem, 0, ram); 6821db09b84Saurel32 6833eddc1beSBharat Bhushan dev = qdev_create(NULL, "e500-ccsr"); 6843eddc1beSBharat Bhushan object_property_add_child(qdev_get_machine(), "e500-ccsr", 6853eddc1beSBharat Bhushan OBJECT(dev), NULL); 6863eddc1beSBharat Bhushan qdev_init_nofail(dev); 6873eddc1beSBharat Bhushan ccsr = CCSR(dev); 6883eddc1beSBharat Bhushan ccsr_addr_space = &ccsr->ccsr_space; 6893eddc1beSBharat Bhushan memory_region_add_subregion(address_space_mem, MPC8544_CCSRBAR_BASE, 6903eddc1beSBharat Bhushan ccsr_addr_space); 691dffb1dc2SBharat Bhushan 69282fc73b6SScott Wood mpic = ppce500_init_mpic(params, ccsr_addr_space, irqs); 6931db09b84Saurel32 6941db09b84Saurel32 /* Serial */ 6952d48377aSBlue Swirl if (serial_hds[0]) { 6963eddc1beSBharat Bhushan serial_mm_init(ccsr_addr_space, MPC8544_SERIAL0_REGS_OFFSET, 697cdbb912aSAlexander Graf 0, mpic[42], 399193, 6982ff0c7c3SRichard Henderson serial_hds[0], DEVICE_BIG_ENDIAN); 6992d48377aSBlue Swirl } 7001db09b84Saurel32 7012d48377aSBlue Swirl if (serial_hds[1]) { 7023eddc1beSBharat Bhushan serial_mm_init(ccsr_addr_space, MPC8544_SERIAL1_REGS_OFFSET, 703cdbb912aSAlexander Graf 0, mpic[42], 399193, 70459de4f98SBharat Bhushan serial_hds[1], DEVICE_BIG_ENDIAN); 7052d48377aSBlue Swirl } 7061db09b84Saurel32 707b0fb8423SAlexander Graf /* General Utility device */ 708dffb1dc2SBharat Bhushan dev = qdev_create(NULL, "mpc8544-guts"); 709dffb1dc2SBharat Bhushan qdev_init_nofail(dev); 710dffb1dc2SBharat Bhushan s = SYS_BUS_DEVICE(dev); 7113eddc1beSBharat Bhushan memory_region_add_subregion(ccsr_addr_space, MPC8544_UTIL_OFFSET, 712dffb1dc2SBharat Bhushan sysbus_mmio_get_region(s, 0)); 713b0fb8423SAlexander Graf 7141db09b84Saurel32 /* PCI */ 715dffb1dc2SBharat Bhushan dev = qdev_create(NULL, "e500-pcihost"); 716492ec48dSAlexander Graf qdev_prop_set_uint32(dev, "first_slot", params->pci_first_slot); 717dffb1dc2SBharat Bhushan qdev_init_nofail(dev); 718dffb1dc2SBharat Bhushan s = SYS_BUS_DEVICE(dev); 719dffb1dc2SBharat Bhushan sysbus_connect_irq(s, 0, mpic[pci_irq_nrs[0]]); 720dffb1dc2SBharat Bhushan sysbus_connect_irq(s, 1, mpic[pci_irq_nrs[1]]); 721dffb1dc2SBharat Bhushan sysbus_connect_irq(s, 2, mpic[pci_irq_nrs[2]]); 722dffb1dc2SBharat Bhushan sysbus_connect_irq(s, 3, mpic[pci_irq_nrs[3]]); 7233eddc1beSBharat Bhushan memory_region_add_subregion(ccsr_addr_space, MPC8544_PCI_REGS_OFFSET, 724dffb1dc2SBharat Bhushan sysbus_mmio_get_region(s, 0)); 725dffb1dc2SBharat Bhushan 726d461e3b9SAlexander Graf pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0"); 7271db09b84Saurel32 if (!pci_bus) 7281db09b84Saurel32 printf("couldn't create PCI controller!\n"); 7291db09b84Saurel32 7301356b98dSAndreas Färber sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, MPC8544_PCI_IO); 7311db09b84Saurel32 7321db09b84Saurel32 if (pci_bus) { 7331db09b84Saurel32 /* Register network interfaces. */ 7341db09b84Saurel32 for (i = 0; i < nb_nics; i++) { 73529b358f9SDavid Gibson pci_nic_init_nofail(&nd_table[i], pci_bus, "virtio", NULL); 7361db09b84Saurel32 } 7371db09b84Saurel32 } 7381db09b84Saurel32 7395c145dacSAlexander Graf /* Register spinning region */ 7405c145dacSAlexander Graf sysbus_create_simple("e500-spin", MPC8544_SPIN_BASE, NULL); 7415c145dacSAlexander Graf 7421db09b84Saurel32 /* Load kernel. */ 74392238367SMarkus Armbruster if (args->kernel_filename) { 74492238367SMarkus Armbruster kernel_size = load_uimage(args->kernel_filename, &entry, 745e6eaabebSScott Wood &loadaddr, NULL); 7461db09b84Saurel32 if (kernel_size < 0) { 74792238367SMarkus Armbruster kernel_size = load_elf(args->kernel_filename, NULL, NULL, 748e6eaabebSScott Wood &elf_entry, &elf_lowaddr, NULL, 1, 749e6eaabebSScott Wood ELF_MACHINE, 0); 7501db09b84Saurel32 entry = elf_entry; 7511db09b84Saurel32 loadaddr = elf_lowaddr; 7521db09b84Saurel32 } 7531db09b84Saurel32 /* XXX try again as binary */ 7541db09b84Saurel32 if (kernel_size < 0) { 7551db09b84Saurel32 fprintf(stderr, "qemu: could not load kernel '%s'\n", 75692238367SMarkus Armbruster args->kernel_filename); 7571db09b84Saurel32 exit(1); 7581db09b84Saurel32 } 759528e536eSAlexander Graf 760528e536eSAlexander Graf cur_base = loadaddr + kernel_size; 761b8dec144SAlexander Graf 762b8dec144SAlexander Graf /* Reserve space for dtb */ 763b8dec144SAlexander Graf dt_base = (cur_base + DTC_LOAD_PAD) & ~DTC_PAD_MASK; 764b8dec144SAlexander Graf cur_base += DTB_MAX_SIZE; 7651db09b84Saurel32 } 7661db09b84Saurel32 7671db09b84Saurel32 /* Load initrd. */ 76892238367SMarkus Armbruster if (args->initrd_filename) { 769528e536eSAlexander Graf initrd_base = (cur_base + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK; 77092238367SMarkus Armbruster initrd_size = load_image_targphys(args->initrd_filename, initrd_base, 771d7585251Spbrook ram_size - initrd_base); 7721db09b84Saurel32 7731db09b84Saurel32 if (initrd_size < 0) { 7741db09b84Saurel32 fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", 77592238367SMarkus Armbruster args->initrd_filename); 7761db09b84Saurel32 exit(1); 7771db09b84Saurel32 } 778528e536eSAlexander Graf 779528e536eSAlexander Graf cur_base = initrd_base + initrd_size; 7801db09b84Saurel32 } 7811db09b84Saurel32 7821db09b84Saurel32 /* If we're loading a kernel directly, we must load the device tree too. */ 78392238367SMarkus Armbruster if (args->kernel_filename) { 7845c145dacSAlexander Graf struct boot_info *boot_info; 785cba2026aSAlexander Graf int dt_size; 7865c145dacSAlexander Graf 78728290f37SAlexander Graf dt_size = ppce500_prep_device_tree(args, params, dt_base, 78892238367SMarkus Armbruster initrd_base, initrd_size); 789cba2026aSAlexander Graf if (dt_size < 0) { 7901db09b84Saurel32 fprintf(stderr, "couldn't load device tree\n"); 7911db09b84Saurel32 exit(1); 7921db09b84Saurel32 } 793b8dec144SAlexander Graf assert(dt_size < DTB_MAX_SIZE); 7941db09b84Saurel32 795e61c36d5SAlexander Graf boot_info = env->load_info; 7963b989d49SAlexander Graf boot_info->entry = entry; 7973b989d49SAlexander Graf boot_info->dt_base = dt_base; 798cba2026aSAlexander Graf boot_info->dt_size = dt_size; 7991db09b84Saurel32 } 8001db09b84Saurel32 8013b989d49SAlexander Graf if (kvm_enabled()) { 8021db09b84Saurel32 kvmppc_init(); 8033b989d49SAlexander Graf } 8041db09b84Saurel32 } 8053eddc1beSBharat Bhushan 8063eddc1beSBharat Bhushan static int e500_ccsr_initfn(SysBusDevice *dev) 8073eddc1beSBharat Bhushan { 8083eddc1beSBharat Bhushan PPCE500CCSRState *ccsr; 8093eddc1beSBharat Bhushan 8103eddc1beSBharat Bhushan ccsr = CCSR(dev); 81140c5dce9SPaolo Bonzini memory_region_init(&ccsr->ccsr_space, OBJECT(ccsr), "e500-ccsr", 8123eddc1beSBharat Bhushan MPC8544_CCSRBAR_SIZE); 8133eddc1beSBharat Bhushan return 0; 8143eddc1beSBharat Bhushan } 8153eddc1beSBharat Bhushan 8163eddc1beSBharat Bhushan static void e500_ccsr_class_init(ObjectClass *klass, void *data) 8173eddc1beSBharat Bhushan { 8183eddc1beSBharat Bhushan SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); 8193eddc1beSBharat Bhushan k->init = e500_ccsr_initfn; 8203eddc1beSBharat Bhushan } 8213eddc1beSBharat Bhushan 8223eddc1beSBharat Bhushan static const TypeInfo e500_ccsr_info = { 8233eddc1beSBharat Bhushan .name = TYPE_CCSR, 8243eddc1beSBharat Bhushan .parent = TYPE_SYS_BUS_DEVICE, 8253eddc1beSBharat Bhushan .instance_size = sizeof(PPCE500CCSRState), 8263eddc1beSBharat Bhushan .class_init = e500_ccsr_class_init, 8273eddc1beSBharat Bhushan }; 8283eddc1beSBharat Bhushan 8293eddc1beSBharat Bhushan static void e500_register_types(void) 8303eddc1beSBharat Bhushan { 8313eddc1beSBharat Bhushan type_register_static(&e500_ccsr_info); 8323eddc1beSBharat Bhushan } 8333eddc1beSBharat Bhushan 8343eddc1beSBharat Bhushan type_init(e500_register_types) 835