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" 429dd5eba1SScott Wood #define DTC_LOAD_PAD 0x1800000 4375bb6589SLiu Yu #define DTC_PAD_MASK 0xFFFFF 44b8dec144SAlexander Graf #define DTB_MAX_SIZE (8 * 1024 * 1024) 4575bb6589SLiu Yu #define INITRD_LOAD_PAD 0x2000000 4675bb6589SLiu Yu #define INITRD_PAD_MASK 0xFFFFFF 471db09b84Saurel32 481db09b84Saurel32 #define RAM_SIZES_ALIGN (64UL << 20) 491db09b84Saurel32 50b3305981SScott Wood /* TODO: parameterize */ 51ed2bc496SAlexander Graf #define MPC8544_CCSRBAR_BASE 0xE0000000ULL 52ed2bc496SAlexander Graf #define MPC8544_CCSRBAR_SIZE 0x00100000ULL 53dffb1dc2SBharat Bhushan #define MPC8544_MPIC_REGS_OFFSET 0x40000ULL 54a911b7a9SAlexander Graf #define MPC8544_MSI_REGS_OFFSET 0x41600ULL 55dffb1dc2SBharat Bhushan #define MPC8544_SERIAL0_REGS_OFFSET 0x4500ULL 56dffb1dc2SBharat Bhushan #define MPC8544_SERIAL1_REGS_OFFSET 0x4600ULL 57dffb1dc2SBharat Bhushan #define MPC8544_PCI_REGS_OFFSET 0x8000ULL 58dffb1dc2SBharat Bhushan #define MPC8544_PCI_REGS_BASE (MPC8544_CCSRBAR_BASE + \ 59dffb1dc2SBharat Bhushan MPC8544_PCI_REGS_OFFSET) 60ed2bc496SAlexander Graf #define MPC8544_PCI_REGS_SIZE 0x1000ULL 61ed2bc496SAlexander Graf #define MPC8544_PCI_IO 0xE1000000ULL 62dffb1dc2SBharat Bhushan #define MPC8544_UTIL_OFFSET 0xe0000ULL 63ed2bc496SAlexander Graf #define MPC8544_SPIN_BASE 0xEF000000ULL 64*b88e77f4SAlexander Graf #define MPC8XXX_GPIO_OFFSET 0x000FF000ULL 65*b88e77f4SAlexander Graf #define MPC8XXX_GPIO_IRQ 43 661db09b84Saurel32 673b989d49SAlexander Graf struct boot_info 683b989d49SAlexander Graf { 693b989d49SAlexander Graf uint32_t dt_base; 70cba2026aSAlexander Graf uint32_t dt_size; 713b989d49SAlexander Graf uint32_t entry; 723b989d49SAlexander Graf }; 733b989d49SAlexander Graf 74347dd79dSAlexander Graf static uint32_t *pci_map_create(void *fdt, uint32_t mpic, int first_slot, 75347dd79dSAlexander Graf int nr_slots, int *len) 760dbc0798SAlexander Graf { 77347dd79dSAlexander Graf int i = 0; 78347dd79dSAlexander Graf int slot; 79347dd79dSAlexander Graf int pci_irq; 809e2c1298SAlexander Graf int host_irq; 81347dd79dSAlexander Graf int last_slot = first_slot + nr_slots; 82347dd79dSAlexander Graf uint32_t *pci_map; 830dbc0798SAlexander Graf 84347dd79dSAlexander Graf *len = nr_slots * 4 * 7 * sizeof(uint32_t); 85347dd79dSAlexander Graf pci_map = g_malloc(*len); 86347dd79dSAlexander Graf 87347dd79dSAlexander Graf for (slot = first_slot; slot < last_slot; slot++) { 88347dd79dSAlexander Graf for (pci_irq = 0; pci_irq < 4; pci_irq++) { 89347dd79dSAlexander Graf pci_map[i++] = cpu_to_be32(slot << 11); 90347dd79dSAlexander Graf pci_map[i++] = cpu_to_be32(0x0); 91347dd79dSAlexander Graf pci_map[i++] = cpu_to_be32(0x0); 92347dd79dSAlexander Graf pci_map[i++] = cpu_to_be32(pci_irq + 1); 93347dd79dSAlexander Graf pci_map[i++] = cpu_to_be32(mpic); 949e2c1298SAlexander Graf host_irq = ppce500_pci_map_irq_slot(slot, pci_irq); 959e2c1298SAlexander Graf pci_map[i++] = cpu_to_be32(host_irq + 1); 96347dd79dSAlexander Graf pci_map[i++] = cpu_to_be32(0x1); 970dbc0798SAlexander Graf } 980dbc0798SAlexander Graf } 990dbc0798SAlexander Graf 100347dd79dSAlexander Graf assert((i * sizeof(uint32_t)) == *len); 101347dd79dSAlexander Graf 102347dd79dSAlexander Graf return pci_map; 103347dd79dSAlexander Graf } 104347dd79dSAlexander Graf 105a053a7ceSAlexander Graf static void dt_serial_create(void *fdt, unsigned long long offset, 106a053a7ceSAlexander Graf const char *soc, const char *mpic, 107a053a7ceSAlexander Graf const char *alias, int idx, bool defcon) 108a053a7ceSAlexander Graf { 109a053a7ceSAlexander Graf char ser[128]; 110a053a7ceSAlexander Graf 111a053a7ceSAlexander Graf snprintf(ser, sizeof(ser), "%s/serial@%llx", soc, offset); 1125a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, ser); 1135a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, ser, "device_type", "serial"); 1145a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, ser, "compatible", "ns16550"); 1155a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, ser, "reg", offset, 0x100); 1165a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, ser, "cell-index", idx); 1175a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, ser, "clock-frequency", 0); 1185a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, ser, "interrupts", 42, 2); 1195a4348d1SPeter Crosthwaite qemu_fdt_setprop_phandle(fdt, ser, "interrupt-parent", mpic); 1205a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, "/aliases", alias, ser); 121a053a7ceSAlexander Graf 122a053a7ceSAlexander Graf if (defcon) { 1235a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, "/chosen", "linux,stdout-path", ser); 124a053a7ceSAlexander Graf } 125a053a7ceSAlexander Graf } 126a053a7ceSAlexander Graf 127*b88e77f4SAlexander Graf static void create_dt_mpc8xxx_gpio(void *fdt, const char *soc, const char *mpic) 128*b88e77f4SAlexander Graf { 129*b88e77f4SAlexander Graf hwaddr mmio0 = MPC8XXX_GPIO_OFFSET; 130*b88e77f4SAlexander Graf int irq0 = MPC8XXX_GPIO_IRQ; 131*b88e77f4SAlexander Graf gchar *node = g_strdup_printf("%s/gpio@%"PRIx64, soc, mmio0); 132*b88e77f4SAlexander Graf 133*b88e77f4SAlexander Graf qemu_fdt_add_subnode(fdt, node); 134*b88e77f4SAlexander Graf qemu_fdt_setprop_string(fdt, node, "compatible", "fsl,qoriq-gpio"); 135*b88e77f4SAlexander Graf qemu_fdt_setprop_cells(fdt, node, "reg", mmio0, 0x1000); 136*b88e77f4SAlexander Graf qemu_fdt_setprop_cells(fdt, node, "interrupts", irq0, 0x2); 137*b88e77f4SAlexander Graf qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", mpic); 138*b88e77f4SAlexander Graf qemu_fdt_setprop_cells(fdt, node, "#gpio-cells", 2); 139*b88e77f4SAlexander Graf qemu_fdt_setprop(fdt, node, "gpio-controller", NULL, 0); 140*b88e77f4SAlexander Graf 141*b88e77f4SAlexander Graf g_free(node); 142*b88e77f4SAlexander Graf } 143*b88e77f4SAlexander Graf 1443ef96221SMarcel Apfelbaum static int ppce500_load_device_tree(MachineState *machine, 145e6eaabebSScott Wood PPCE500Params *params, 146a8170e5eSAvi Kivity hwaddr addr, 147a8170e5eSAvi Kivity hwaddr initrd_base, 14828290f37SAlexander Graf hwaddr initrd_size, 149903585deSAlexander Graf hwaddr kernel_base, 150903585deSAlexander Graf hwaddr kernel_size, 15128290f37SAlexander Graf bool dry_run) 1521db09b84Saurel32 { 15328290f37SAlexander Graf CPUPPCState *env = first_cpu->env_ptr; 154dbf916d8SAurelien Jarno int ret = -1; 1553ef96221SMarcel Apfelbaum uint64_t mem_reg_property[] = { 0, cpu_to_be64(machine->ram_size) }; 1567ec632b4Spbrook int fdt_size; 157dbf916d8SAurelien Jarno void *fdt; 1585de6b46dSAlexander Graf uint8_t hypercall[16]; 159911d6e7aSAlexander Graf uint32_t clock_freq = 400000000; 160911d6e7aSAlexander Graf uint32_t tb_freq = 400000000; 161621d05e3SAlexander Graf int i; 162ebb9518aSAlexander Graf char compatible_sb[] = "fsl,mpc8544-immr\0simple-bus"; 1635da96624SAlexander Graf char soc[128]; 16419ac9deaSAlexander Graf char mpic[128]; 16519ac9deaSAlexander Graf uint32_t mpic_ph; 166a911b7a9SAlexander Graf uint32_t msi_ph; 167f5038483SAlexander Graf char gutil[128]; 1680dbc0798SAlexander Graf char pci[128]; 169a911b7a9SAlexander Graf char msi[128]; 170347dd79dSAlexander Graf uint32_t *pci_map = NULL; 171347dd79dSAlexander Graf int len; 1723627757eSAlexander Graf uint32_t pci_ranges[14] = 1733627757eSAlexander Graf { 1743627757eSAlexander Graf 0x2000000, 0x0, 0xc0000000, 1753627757eSAlexander Graf 0x0, 0xc0000000, 1763627757eSAlexander Graf 0x0, 0x20000000, 1773627757eSAlexander Graf 1783627757eSAlexander Graf 0x1000000, 0x0, 0x0, 1793627757eSAlexander Graf 0x0, 0xe1000000, 1803627757eSAlexander Graf 0x0, 0x10000, 1813627757eSAlexander Graf }; 1822ff3de68SMarkus Armbruster QemuOpts *machine_opts = qemu_get_machine_opts(); 1832ff3de68SMarkus Armbruster const char *dtb_file = qemu_opt_get(machine_opts, "dtb"); 1842ff3de68SMarkus Armbruster const char *toplevel_compat = qemu_opt_get(machine_opts, "dt_compatible"); 185d1b93565SAlexander Graf 186d1b93565SAlexander Graf if (dtb_file) { 187d1b93565SAlexander Graf char *filename; 188d1b93565SAlexander Graf filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_file); 189d1b93565SAlexander Graf if (!filename) { 190d1b93565SAlexander Graf goto out; 191d1b93565SAlexander Graf } 192d1b93565SAlexander Graf 193d1b93565SAlexander Graf fdt = load_device_tree(filename, &fdt_size); 194d1b93565SAlexander Graf if (!fdt) { 195d1b93565SAlexander Graf goto out; 196d1b93565SAlexander Graf } 197d1b93565SAlexander Graf goto done; 198d1b93565SAlexander Graf } 1991db09b84Saurel32 2002636fcb6SAlexander Graf fdt = create_device_tree(&fdt_size); 2015cea8590SPaul Brook if (fdt == NULL) { 2025cea8590SPaul Brook goto out; 2035cea8590SPaul Brook } 2041db09b84Saurel32 2051db09b84Saurel32 /* Manipulate device tree in memory. */ 2065a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 2); 2075a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 2); 20851b852b7SAlexander Graf 2095a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, "/memory"); 2105a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, "/memory", "device_type", "memory"); 2115a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, "/memory", "reg", mem_reg_property, 2121db09b84Saurel32 sizeof(mem_reg_property)); 2131db09b84Saurel32 2145a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, "/chosen"); 2153b989d49SAlexander Graf if (initrd_size) { 2165a4348d1SPeter Crosthwaite ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start", 2171db09b84Saurel32 initrd_base); 2183b989d49SAlexander Graf if (ret < 0) { 2191db09b84Saurel32 fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n"); 2203b989d49SAlexander Graf } 2211db09b84Saurel32 2225a4348d1SPeter Crosthwaite ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end", 2231db09b84Saurel32 (initrd_base + initrd_size)); 2243b989d49SAlexander Graf if (ret < 0) { 2251db09b84Saurel32 fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n"); 2263b989d49SAlexander Graf } 227903585deSAlexander Graf 228903585deSAlexander Graf } 229903585deSAlexander Graf 230903585deSAlexander Graf if (kernel_base != -1ULL) { 231903585deSAlexander Graf qemu_fdt_setprop_cells(fdt, "/chosen", "qemu,boot-kernel", 232903585deSAlexander Graf kernel_base >> 32, kernel_base, 233903585deSAlexander Graf kernel_size >> 32, kernel_size); 2343b989d49SAlexander Graf } 2351db09b84Saurel32 2365a4348d1SPeter Crosthwaite ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", 2373ef96221SMarcel Apfelbaum machine->kernel_cmdline); 2381db09b84Saurel32 if (ret < 0) 2391db09b84Saurel32 fprintf(stderr, "couldn't set /chosen/bootargs\n"); 2401db09b84Saurel32 2411db09b84Saurel32 if (kvm_enabled()) { 242911d6e7aSAlexander Graf /* Read out host's frequencies */ 243911d6e7aSAlexander Graf clock_freq = kvmppc_get_clockfreq(); 244911d6e7aSAlexander Graf tb_freq = kvmppc_get_tbfreq(); 2455de6b46dSAlexander Graf 2465de6b46dSAlexander Graf /* indicate KVM hypercall interface */ 2475a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, "/hypervisor"); 2485a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, "/hypervisor", "compatible", 2495de6b46dSAlexander Graf "linux,kvm"); 2505de6b46dSAlexander Graf kvmppc_get_hypercall(env, hypercall, sizeof(hypercall)); 2515a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, "/hypervisor", "hcall-instructions", 2525de6b46dSAlexander Graf hypercall, sizeof(hypercall)); 2531a61a9aeSStuart Yoder /* if KVM supports the idle hcall, set property indicating this */ 2541a61a9aeSStuart Yoder if (kvmppc_get_hasidle(env)) { 2555a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, "/hypervisor", "has-idle", NULL, 0); 2561a61a9aeSStuart Yoder } 2571db09b84Saurel32 } 2581db09b84Saurel32 259625e665bSAlexander Graf /* Create CPU nodes */ 2605a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, "/cpus"); 2615a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 1); 2625a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0); 263625e665bSAlexander Graf 2641e3debf0SAlexander Graf /* We need to generate the cpu nodes in reverse order, so Linux can pick 2651e3debf0SAlexander Graf the first node as boot node and be happy */ 2661e3debf0SAlexander Graf for (i = smp_cpus - 1; i >= 0; i--) { 267440c8152SAndreas Färber CPUState *cpu; 2680f20ba62SAlexey Kardashevskiy PowerPCCPU *pcpu; 269621d05e3SAlexander Graf char cpu_name[128]; 2701d2e5c52SAlexander Graf uint64_t cpu_release_addr = MPC8544_SPIN_BASE + (i * 0x20); 27110f25a46SAlexander Graf 272440c8152SAndreas Färber cpu = qemu_get_cpu(i); 27355e5c285SAndreas Färber if (cpu == NULL) { 2741e3debf0SAlexander Graf continue; 2751e3debf0SAlexander Graf } 276440c8152SAndreas Färber env = cpu->env_ptr; 2770f20ba62SAlexey Kardashevskiy pcpu = POWERPC_CPU(cpu); 2781e3debf0SAlexander Graf 27955e5c285SAndreas Färber snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x", 2800f20ba62SAlexey Kardashevskiy ppc_get_vcpu_dt_id(pcpu)); 2815a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, cpu_name); 2825a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq); 2835a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq); 2845a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, cpu_name, "device_type", "cpu"); 2850f20ba62SAlexey Kardashevskiy qemu_fdt_setprop_cell(fdt, cpu_name, "reg", 2860f20ba62SAlexey Kardashevskiy ppc_get_vcpu_dt_id(pcpu)); 2875a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-line-size", 2881e3debf0SAlexander Graf env->dcache_line_size); 2895a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-line-size", 2901e3debf0SAlexander Graf env->icache_line_size); 2915a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-size", 0x8000); 2925a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-size", 0x8000); 2935a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "bus-frequency", 0); 29455e5c285SAndreas Färber if (cpu->cpu_index) { 2955a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, cpu_name, "status", "disabled"); 2965a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, cpu_name, "enable-method", 2975a4348d1SPeter Crosthwaite "spin-table"); 2985a4348d1SPeter Crosthwaite qemu_fdt_setprop_u64(fdt, cpu_name, "cpu-release-addr", 2991d2e5c52SAlexander Graf cpu_release_addr); 3001e3debf0SAlexander Graf } else { 3015a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, cpu_name, "status", "okay"); 3021e3debf0SAlexander Graf } 3031db09b84Saurel32 } 3041db09b84Saurel32 3055a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, "/aliases"); 3065da96624SAlexander Graf /* XXX These should go into their respective devices' code */ 307ed2bc496SAlexander Graf snprintf(soc, sizeof(soc), "/soc@%llx", MPC8544_CCSRBAR_BASE); 3085a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, soc); 3095a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, soc, "device_type", "soc"); 3105a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, soc, "compatible", compatible_sb, 311ebb9518aSAlexander Graf sizeof(compatible_sb)); 3125a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, soc, "#address-cells", 1); 3135a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, soc, "#size-cells", 1); 3145a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, soc, "ranges", 0x0, 3153627757eSAlexander Graf MPC8544_CCSRBAR_BASE >> 32, MPC8544_CCSRBAR_BASE, 3165da96624SAlexander Graf MPC8544_CCSRBAR_SIZE); 3175da96624SAlexander Graf /* XXX should contain a reasonable value */ 3185a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, soc, "bus-frequency", 0); 3195da96624SAlexander Graf 320dffb1dc2SBharat Bhushan snprintf(mpic, sizeof(mpic), "%s/pic@%llx", soc, MPC8544_MPIC_REGS_OFFSET); 3215a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, mpic); 3225a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, mpic, "device_type", "open-pic"); 3235a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, mpic, "compatible", "fsl,mpic"); 3245a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_OFFSET, 325dffb1dc2SBharat Bhushan 0x40000); 3265a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, mpic, "#address-cells", 0); 3275a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, mpic, "#interrupt-cells", 2); 3285a4348d1SPeter Crosthwaite mpic_ph = qemu_fdt_alloc_phandle(fdt); 3295a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, mpic, "phandle", mpic_ph); 3305a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, mpic, "linux,phandle", mpic_ph); 3315a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, mpic, "interrupt-controller", NULL, 0); 33219ac9deaSAlexander Graf 3330cfc6e8dSAlexander Graf /* 3340cfc6e8dSAlexander Graf * We have to generate ser1 first, because Linux takes the first 3350cfc6e8dSAlexander Graf * device it finds in the dt as serial output device. And we generate 3360cfc6e8dSAlexander Graf * devices in reverse order to the dt. 3370cfc6e8dSAlexander Graf */ 33879c0ff2cSAlexander Graf if (serial_hds[1]) { 339dffb1dc2SBharat Bhushan dt_serial_create(fdt, MPC8544_SERIAL1_REGS_OFFSET, 340a053a7ceSAlexander Graf soc, mpic, "serial1", 1, false); 34179c0ff2cSAlexander Graf } 34279c0ff2cSAlexander Graf 34379c0ff2cSAlexander Graf if (serial_hds[0]) { 344dffb1dc2SBharat Bhushan dt_serial_create(fdt, MPC8544_SERIAL0_REGS_OFFSET, 345a053a7ceSAlexander Graf soc, mpic, "serial0", 0, true); 34679c0ff2cSAlexander Graf } 3470cfc6e8dSAlexander Graf 348ed2bc496SAlexander Graf snprintf(gutil, sizeof(gutil), "%s/global-utilities@%llx", soc, 349dffb1dc2SBharat Bhushan MPC8544_UTIL_OFFSET); 3505a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, gutil); 3515a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, gutil, "compatible", "fsl,mpc8544-guts"); 3525a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, gutil, "reg", MPC8544_UTIL_OFFSET, 0x1000); 3535a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, gutil, "fsl,has-rstcr", NULL, 0); 354f5038483SAlexander Graf 355a911b7a9SAlexander Graf snprintf(msi, sizeof(msi), "/%s/msi@%llx", soc, MPC8544_MSI_REGS_OFFSET); 3565a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, msi); 3575a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, msi, "compatible", "fsl,mpic-msi"); 3585a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, msi, "reg", MPC8544_MSI_REGS_OFFSET, 0x200); 3595a4348d1SPeter Crosthwaite msi_ph = qemu_fdt_alloc_phandle(fdt); 3605a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, msi, "msi-available-ranges", 0x0, 0x100); 3615a4348d1SPeter Crosthwaite qemu_fdt_setprop_phandle(fdt, msi, "interrupt-parent", mpic); 3625a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, msi, "interrupts", 363a911b7a9SAlexander Graf 0xe0, 0x0, 364a911b7a9SAlexander Graf 0xe1, 0x0, 365a911b7a9SAlexander Graf 0xe2, 0x0, 366a911b7a9SAlexander Graf 0xe3, 0x0, 367a911b7a9SAlexander Graf 0xe4, 0x0, 368a911b7a9SAlexander Graf 0xe5, 0x0, 369a911b7a9SAlexander Graf 0xe6, 0x0, 370a911b7a9SAlexander Graf 0xe7, 0x0); 3715a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, msi, "phandle", msi_ph); 3725a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, msi, "linux,phandle", msi_ph); 373a911b7a9SAlexander Graf 374ed2bc496SAlexander Graf snprintf(pci, sizeof(pci), "/pci@%llx", MPC8544_PCI_REGS_BASE); 3755a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, pci); 3765a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, pci, "cell-index", 0); 3775a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, pci, "compatible", "fsl,mpc8540-pci"); 3785a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, pci, "device_type", "pci"); 3795a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, pci, "interrupt-map-mask", 0xf800, 0x0, 3800dbc0798SAlexander Graf 0x0, 0x7); 3815a4348d1SPeter Crosthwaite pci_map = pci_map_create(fdt, qemu_fdt_get_phandle(fdt, mpic), 382492ec48dSAlexander Graf params->pci_first_slot, params->pci_nr_slots, 383492ec48dSAlexander Graf &len); 3845a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, pci, "interrupt-map", pci_map, len); 3855a4348d1SPeter Crosthwaite qemu_fdt_setprop_phandle(fdt, pci, "interrupt-parent", mpic); 3865a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, pci, "interrupts", 24, 2); 3875a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, pci, "bus-range", 0, 255); 3883627757eSAlexander Graf for (i = 0; i < 14; i++) { 3890dbc0798SAlexander Graf pci_ranges[i] = cpu_to_be32(pci_ranges[i]); 3900dbc0798SAlexander Graf } 3915a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, pci, "fsl,msi", msi_ph); 3925a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, pci, "ranges", pci_ranges, sizeof(pci_ranges)); 3935a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, pci, "reg", MPC8544_PCI_REGS_BASE >> 32, 3943627757eSAlexander Graf MPC8544_PCI_REGS_BASE, 0, 0x1000); 3955a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, pci, "clock-frequency", 66666666); 3965a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, pci, "#interrupt-cells", 1); 3975a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, pci, "#size-cells", 2); 3985a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, pci, "#address-cells", 3); 3995a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, "/aliases", "pci0", pci); 4000dbc0798SAlexander Graf 401*b88e77f4SAlexander Graf if (params->has_mpc8xxx_gpio) { 402*b88e77f4SAlexander Graf create_dt_mpc8xxx_gpio(fdt, soc, mpic); 403*b88e77f4SAlexander Graf } 404*b88e77f4SAlexander Graf 405e6eaabebSScott Wood params->fixup_devtree(params, fdt); 406e6eaabebSScott Wood 407e6eaabebSScott Wood if (toplevel_compat) { 4085a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, "/", "compatible", toplevel_compat, 409e6eaabebSScott Wood strlen(toplevel_compat) + 1); 410e6eaabebSScott Wood } 411e6eaabebSScott Wood 412d1b93565SAlexander Graf done: 41328290f37SAlexander Graf if (!dry_run) { 4145a4348d1SPeter Crosthwaite qemu_fdt_dumpdtb(fdt, fdt_size); 41528290f37SAlexander Graf cpu_physical_memory_write(addr, fdt, fdt_size); 416cba2026aSAlexander Graf } 417cba2026aSAlexander Graf ret = fdt_size; 4187ec632b4Spbrook 4191db09b84Saurel32 out: 420347dd79dSAlexander Graf g_free(pci_map); 4211db09b84Saurel32 42204088adbSLiu Yu return ret; 4231db09b84Saurel32 } 4241db09b84Saurel32 42528290f37SAlexander Graf typedef struct DeviceTreeParams { 4263ef96221SMarcel Apfelbaum MachineState *machine; 42728290f37SAlexander Graf PPCE500Params params; 42828290f37SAlexander Graf hwaddr addr; 42928290f37SAlexander Graf hwaddr initrd_base; 43028290f37SAlexander Graf hwaddr initrd_size; 431903585deSAlexander Graf hwaddr kernel_base; 432903585deSAlexander Graf hwaddr kernel_size; 43328290f37SAlexander Graf } DeviceTreeParams; 43428290f37SAlexander Graf 43528290f37SAlexander Graf static void ppce500_reset_device_tree(void *opaque) 43628290f37SAlexander Graf { 43728290f37SAlexander Graf DeviceTreeParams *p = opaque; 4383812c71fSAlexander Graf ppce500_load_device_tree(p->machine, &p->params, p->addr, p->initrd_base, 439903585deSAlexander Graf p->initrd_size, p->kernel_base, p->kernel_size, 440903585deSAlexander Graf false); 44128290f37SAlexander Graf } 44228290f37SAlexander Graf 4433ef96221SMarcel Apfelbaum static int ppce500_prep_device_tree(MachineState *machine, 44428290f37SAlexander Graf PPCE500Params *params, 44528290f37SAlexander Graf hwaddr addr, 44628290f37SAlexander Graf hwaddr initrd_base, 447903585deSAlexander Graf hwaddr initrd_size, 448903585deSAlexander Graf hwaddr kernel_base, 449903585deSAlexander Graf hwaddr kernel_size) 45028290f37SAlexander Graf { 45128290f37SAlexander Graf DeviceTreeParams *p = g_new(DeviceTreeParams, 1); 4523ef96221SMarcel Apfelbaum p->machine = machine; 45328290f37SAlexander Graf p->params = *params; 45428290f37SAlexander Graf p->addr = addr; 45528290f37SAlexander Graf p->initrd_base = initrd_base; 45628290f37SAlexander Graf p->initrd_size = initrd_size; 457903585deSAlexander Graf p->kernel_base = kernel_base; 458903585deSAlexander Graf p->kernel_size = kernel_size; 45928290f37SAlexander Graf 46028290f37SAlexander Graf qemu_register_reset(ppce500_reset_device_tree, p); 46128290f37SAlexander Graf 46228290f37SAlexander Graf /* Issue the device tree loader once, so that we get the size of the blob */ 4633ef96221SMarcel Apfelbaum return ppce500_load_device_tree(machine, params, addr, initrd_base, 464903585deSAlexander Graf initrd_size, kernel_base, kernel_size, 465903585deSAlexander Graf true); 46628290f37SAlexander Graf } 46728290f37SAlexander Graf 468cba2026aSAlexander Graf /* Create -kernel TLB entries for BookE. */ 469a8170e5eSAvi Kivity static inline hwaddr booke206_page_size_to_tlb(uint64_t size) 470d1e256feSAlexander Graf { 471cba2026aSAlexander Graf return 63 - clz64(size >> 10); 472d1e256feSAlexander Graf } 473d1e256feSAlexander Graf 474cefd3cdbSBharat Bhushan static int booke206_initial_map_tsize(CPUPPCState *env) 4753b989d49SAlexander Graf { 476cba2026aSAlexander Graf struct boot_info *bi = env->load_info; 477cefd3cdbSBharat Bhushan hwaddr dt_end; 478cba2026aSAlexander Graf int ps; 4793b989d49SAlexander Graf 480cba2026aSAlexander Graf /* Our initial TLB entry needs to cover everything from 0 to 481cba2026aSAlexander Graf the device tree top */ 482cba2026aSAlexander Graf dt_end = bi->dt_base + bi->dt_size; 483cba2026aSAlexander Graf ps = booke206_page_size_to_tlb(dt_end) + 1; 484fb37c302SAlexander Graf if (ps & 1) { 485fb37c302SAlexander Graf /* e500v2 can only do even TLB size bits */ 486fb37c302SAlexander Graf ps++; 487fb37c302SAlexander Graf } 488cefd3cdbSBharat Bhushan return ps; 489cefd3cdbSBharat Bhushan } 490cefd3cdbSBharat Bhushan 491cefd3cdbSBharat Bhushan static uint64_t mmubooke_initial_mapsize(CPUPPCState *env) 492cefd3cdbSBharat Bhushan { 493cefd3cdbSBharat Bhushan int tsize; 494cefd3cdbSBharat Bhushan 495cefd3cdbSBharat Bhushan tsize = booke206_initial_map_tsize(env); 496cefd3cdbSBharat Bhushan return (1ULL << 10 << tsize); 497cefd3cdbSBharat Bhushan } 498cefd3cdbSBharat Bhushan 499cefd3cdbSBharat Bhushan static void mmubooke_create_initial_mapping(CPUPPCState *env) 500cefd3cdbSBharat Bhushan { 501cefd3cdbSBharat Bhushan ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0); 502cefd3cdbSBharat Bhushan hwaddr size; 503cefd3cdbSBharat Bhushan int ps; 504cefd3cdbSBharat Bhushan 505cefd3cdbSBharat Bhushan ps = booke206_initial_map_tsize(env); 506cba2026aSAlexander Graf size = (ps << MAS1_TSIZE_SHIFT); 507d1e256feSAlexander Graf tlb->mas1 = MAS1_VALID | size; 508cba2026aSAlexander Graf tlb->mas2 = 0; 509cba2026aSAlexander Graf tlb->mas7_3 = 0; 510d1e256feSAlexander Graf tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX; 51193dd5e85SScott Wood 51293dd5e85SScott Wood env->tlb_dirty = true; 5133b989d49SAlexander Graf } 5143b989d49SAlexander Graf 515b3305981SScott Wood static void ppce500_cpu_reset_sec(void *opaque) 5165c145dacSAlexander Graf { 51738f92da6SAndreas Färber PowerPCCPU *cpu = opaque; 518259186a7SAndreas Färber CPUState *cs = CPU(cpu); 5195c145dacSAlexander Graf 520259186a7SAndreas Färber cpu_reset(cs); 5215c145dacSAlexander Graf 5225c145dacSAlexander Graf /* Secondary CPU starts in halted state for now. Needs to change when 5235c145dacSAlexander Graf implementing non-kernel boot. */ 524259186a7SAndreas Färber cs->halted = 1; 52527103424SAndreas Färber cs->exception_index = EXCP_HLT; 5263b989d49SAlexander Graf } 5273b989d49SAlexander Graf 528b3305981SScott Wood static void ppce500_cpu_reset(void *opaque) 5293b989d49SAlexander Graf { 53038f92da6SAndreas Färber PowerPCCPU *cpu = opaque; 531259186a7SAndreas Färber CPUState *cs = CPU(cpu); 53238f92da6SAndreas Färber CPUPPCState *env = &cpu->env; 5333b989d49SAlexander Graf struct boot_info *bi = env->load_info; 5343b989d49SAlexander Graf 535259186a7SAndreas Färber cpu_reset(cs); 5363b989d49SAlexander Graf 5373b989d49SAlexander Graf /* Set initial guest state. */ 538259186a7SAndreas Färber cs->halted = 0; 5393b989d49SAlexander Graf env->gpr[1] = (16<<20) - 8; 5403b989d49SAlexander Graf env->gpr[3] = bi->dt_base; 541cefd3cdbSBharat Bhushan env->gpr[4] = 0; 542cefd3cdbSBharat Bhushan env->gpr[5] = 0; 543cefd3cdbSBharat Bhushan env->gpr[6] = EPAPR_MAGIC; 544cefd3cdbSBharat Bhushan env->gpr[7] = mmubooke_initial_mapsize(env); 545cefd3cdbSBharat Bhushan env->gpr[8] = 0; 546cefd3cdbSBharat Bhushan env->gpr[9] = 0; 5473b989d49SAlexander Graf env->nip = bi->entry; 548cba2026aSAlexander Graf mmubooke_create_initial_mapping(env); 5493b989d49SAlexander Graf } 5503b989d49SAlexander Graf 551d85937e6SScott Wood static DeviceState *ppce500_init_mpic_qemu(PPCE500Params *params, 55282fc73b6SScott Wood qemu_irq **irqs) 55382fc73b6SScott Wood { 55482fc73b6SScott Wood DeviceState *dev; 55582fc73b6SScott Wood SysBusDevice *s; 55682fc73b6SScott Wood int i, j, k; 55782fc73b6SScott Wood 558e1766344SAndreas Färber dev = qdev_create(NULL, TYPE_OPENPIC); 55982fc73b6SScott Wood qdev_prop_set_uint32(dev, "model", params->mpic_version); 560d85937e6SScott Wood qdev_prop_set_uint32(dev, "nb_cpus", smp_cpus); 561d85937e6SScott Wood 56282fc73b6SScott Wood qdev_init_nofail(dev); 56382fc73b6SScott Wood s = SYS_BUS_DEVICE(dev); 56482fc73b6SScott Wood 56582fc73b6SScott Wood k = 0; 56682fc73b6SScott Wood for (i = 0; i < smp_cpus; i++) { 56782fc73b6SScott Wood for (j = 0; j < OPENPIC_OUTPUT_NB; j++) { 56882fc73b6SScott Wood sysbus_connect_irq(s, k++, irqs[i][j]); 56982fc73b6SScott Wood } 57082fc73b6SScott Wood } 57182fc73b6SScott Wood 572d85937e6SScott Wood return dev; 573d85937e6SScott Wood } 574d85937e6SScott Wood 575d85937e6SScott Wood static DeviceState *ppce500_init_mpic_kvm(PPCE500Params *params, 576d85937e6SScott Wood qemu_irq **irqs) 577d85937e6SScott Wood { 578d85937e6SScott Wood DeviceState *dev; 579d85937e6SScott Wood CPUState *cs; 580d85937e6SScott Wood int r; 581d85937e6SScott Wood 582dd49c038SAndreas Färber dev = qdev_create(NULL, TYPE_KVM_OPENPIC); 583d85937e6SScott Wood qdev_prop_set_uint32(dev, "model", params->mpic_version); 584d85937e6SScott Wood 585d85937e6SScott Wood r = qdev_init(dev); 586d85937e6SScott Wood if (r) { 587d85937e6SScott Wood return NULL; 588d85937e6SScott Wood } 589d85937e6SScott Wood 590bdc44640SAndreas Färber CPU_FOREACH(cs) { 591d85937e6SScott Wood if (kvm_openpic_connect_vcpu(dev, cs)) { 592d85937e6SScott Wood fprintf(stderr, "%s: failed to connect vcpu to irqchip\n", 593d85937e6SScott Wood __func__); 594d85937e6SScott Wood abort(); 595d85937e6SScott Wood } 596d85937e6SScott Wood } 597d85937e6SScott Wood 598d85937e6SScott Wood return dev; 599d85937e6SScott Wood } 600d85937e6SScott Wood 601d85937e6SScott Wood static qemu_irq *ppce500_init_mpic(PPCE500Params *params, MemoryRegion *ccsr, 602d85937e6SScott Wood qemu_irq **irqs) 603d85937e6SScott Wood { 604d85937e6SScott Wood qemu_irq *mpic; 605d85937e6SScott Wood DeviceState *dev = NULL; 606d85937e6SScott Wood SysBusDevice *s; 607d85937e6SScott Wood int i; 608d85937e6SScott Wood 609aa2ac1daSPeter Crosthwaite mpic = g_new0(qemu_irq, 256); 610d85937e6SScott Wood 611d85937e6SScott Wood if (kvm_enabled()) { 61236ad0e94SMarkus Armbruster QemuOpts *machine_opts = qemu_get_machine_opts(); 61336ad0e94SMarkus Armbruster bool irqchip_allowed = qemu_opt_get_bool(machine_opts, 614d85937e6SScott Wood "kernel_irqchip", true); 61536ad0e94SMarkus Armbruster bool irqchip_required = qemu_opt_get_bool(machine_opts, 616d85937e6SScott Wood "kernel_irqchip", false); 617d85937e6SScott Wood 618d85937e6SScott Wood if (irqchip_allowed) { 619d85937e6SScott Wood dev = ppce500_init_mpic_kvm(params, irqs); 620d85937e6SScott Wood } 621d85937e6SScott Wood 622d85937e6SScott Wood if (irqchip_required && !dev) { 623d85937e6SScott Wood fprintf(stderr, "%s: irqchip requested but unavailable\n", 624d85937e6SScott Wood __func__); 625d85937e6SScott Wood abort(); 626d85937e6SScott Wood } 627d85937e6SScott Wood } 628d85937e6SScott Wood 629d85937e6SScott Wood if (!dev) { 630d85937e6SScott Wood dev = ppce500_init_mpic_qemu(params, irqs); 631d85937e6SScott Wood } 632d85937e6SScott Wood 63382fc73b6SScott Wood for (i = 0; i < 256; i++) { 63482fc73b6SScott Wood mpic[i] = qdev_get_gpio_in(dev, i); 63582fc73b6SScott Wood } 63682fc73b6SScott Wood 637d85937e6SScott Wood s = SYS_BUS_DEVICE(dev); 63882fc73b6SScott Wood memory_region_add_subregion(ccsr, MPC8544_MPIC_REGS_OFFSET, 63982fc73b6SScott Wood s->mmio[0].memory); 64082fc73b6SScott Wood 64182fc73b6SScott Wood return mpic; 64282fc73b6SScott Wood } 64382fc73b6SScott Wood 6443ef96221SMarcel Apfelbaum void ppce500_init(MachineState *machine, PPCE500Params *params) 6451db09b84Saurel32 { 64639186d8aSRichard Henderson MemoryRegion *address_space_mem = get_system_memory(); 6472646c133SAvi Kivity MemoryRegion *ram = g_new(MemoryRegion, 1); 6481db09b84Saurel32 PCIBus *pci_bus; 649e2684c0bSAndreas Färber CPUPPCState *env = NULL; 6503812c71fSAlexander Graf uint64_t loadaddr; 6513812c71fSAlexander Graf hwaddr kernel_base = -1LL; 6523812c71fSAlexander Graf int kernel_size = 0; 6533812c71fSAlexander Graf hwaddr dt_base = 0; 6543812c71fSAlexander Graf hwaddr initrd_base = 0; 6553812c71fSAlexander Graf int initrd_size = 0; 6563812c71fSAlexander Graf hwaddr cur_base = 0; 6573812c71fSAlexander Graf char *filename; 6583812c71fSAlexander Graf hwaddr bios_entry = 0; 6593812c71fSAlexander Graf target_long bios_size; 6603812c71fSAlexander Graf struct boot_info *boot_info; 6613812c71fSAlexander Graf int dt_size; 66282fc73b6SScott Wood int i; 663d575a6ceSBharat Bhushan /* irq num for pin INTA, INTB, INTC and INTD is 1, 2, 3 and 664d575a6ceSBharat Bhushan * 4 respectively */ 665d575a6ceSBharat Bhushan unsigned int pci_irq_nrs[PCI_NUM_PINS] = {1, 2, 3, 4}; 666a915249fSAlexander Graf qemu_irq **irqs, *mpic; 667be13cc7aSAlexander Graf DeviceState *dev; 668e2684c0bSAndreas Färber CPUPPCState *firstenv = NULL; 6693eddc1beSBharat Bhushan MemoryRegion *ccsr_addr_space; 670dffb1dc2SBharat Bhushan SysBusDevice *s; 6713eddc1beSBharat Bhushan PPCE500CCSRState *ccsr; 6721db09b84Saurel32 673e61c36d5SAlexander Graf /* Setup CPUs */ 6743ef96221SMarcel Apfelbaum if (machine->cpu_model == NULL) { 6753ef96221SMarcel Apfelbaum machine->cpu_model = "e500v2_v30"; 676ef250db6SAlexander Graf } 677ef250db6SAlexander Graf 678a915249fSAlexander Graf irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *)); 679a915249fSAlexander Graf irqs[0] = g_malloc0(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB); 680e61c36d5SAlexander Graf for (i = 0; i < smp_cpus; i++) { 681397b457dSAndreas Färber PowerPCCPU *cpu; 68255e5c285SAndreas Färber CPUState *cs; 683e61c36d5SAlexander Graf qemu_irq *input; 684397b457dSAndreas Färber 6853ef96221SMarcel Apfelbaum cpu = cpu_ppc_init(machine->cpu_model); 686397b457dSAndreas Färber if (cpu == NULL) { 6871db09b84Saurel32 fprintf(stderr, "Unable to initialize CPU!\n"); 6881db09b84Saurel32 exit(1); 6891db09b84Saurel32 } 690397b457dSAndreas Färber env = &cpu->env; 69155e5c285SAndreas Färber cs = CPU(cpu); 6921db09b84Saurel32 693e61c36d5SAlexander Graf if (!firstenv) { 694e61c36d5SAlexander Graf firstenv = env; 695e61c36d5SAlexander Graf } 696e61c36d5SAlexander Graf 697a915249fSAlexander Graf irqs[i] = irqs[0] + (i * OPENPIC_OUTPUT_NB); 698a915249fSAlexander Graf input = (qemu_irq *)env->irq_inputs; 699a915249fSAlexander Graf irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT]; 700a915249fSAlexander Graf irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT]; 7016a450df9SAlexander Graf env->spr_cb[SPR_BOOKE_PIR].default_value = cs->cpu_index = i; 70268c2dd70SAlexander Graf env->mpic_iack = MPC8544_CCSRBAR_BASE + 703bd25922eSScott Wood MPC8544_MPIC_REGS_OFFSET + 0xa0; 704e61c36d5SAlexander Graf 705a34a92b9SAndreas Färber ppc_booke_timers_init(cpu, 400000000, PPC_TIMER_E500); 7063b989d49SAlexander Graf 7073b989d49SAlexander Graf /* Register reset handler */ 7085c145dacSAlexander Graf if (!i) { 7095c145dacSAlexander Graf /* Primary CPU */ 7105c145dacSAlexander Graf struct boot_info *boot_info; 711e61c36d5SAlexander Graf boot_info = g_malloc0(sizeof(struct boot_info)); 712b3305981SScott Wood qemu_register_reset(ppce500_cpu_reset, cpu); 713e61c36d5SAlexander Graf env->load_info = boot_info; 7145c145dacSAlexander Graf } else { 7155c145dacSAlexander Graf /* Secondary CPUs */ 716b3305981SScott Wood qemu_register_reset(ppce500_cpu_reset_sec, cpu); 7175c145dacSAlexander Graf } 718e61c36d5SAlexander Graf } 719e61c36d5SAlexander Graf 720e61c36d5SAlexander Graf env = firstenv; 7213b989d49SAlexander Graf 7221db09b84Saurel32 /* Fixup Memory size on a alignment boundary */ 7231db09b84Saurel32 ram_size &= ~(RAM_SIZES_ALIGN - 1); 7243ef96221SMarcel Apfelbaum machine->ram_size = ram_size; 7251db09b84Saurel32 7261db09b84Saurel32 /* Register Memory */ 727e938ba0cSShreyas B. Prabhu memory_region_allocate_system_memory(ram, NULL, "mpc8544ds.ram", ram_size); 7282646c133SAvi Kivity memory_region_add_subregion(address_space_mem, 0, ram); 7291db09b84Saurel32 7303eddc1beSBharat Bhushan dev = qdev_create(NULL, "e500-ccsr"); 7313eddc1beSBharat Bhushan object_property_add_child(qdev_get_machine(), "e500-ccsr", 7323eddc1beSBharat Bhushan OBJECT(dev), NULL); 7333eddc1beSBharat Bhushan qdev_init_nofail(dev); 7343eddc1beSBharat Bhushan ccsr = CCSR(dev); 7353eddc1beSBharat Bhushan ccsr_addr_space = &ccsr->ccsr_space; 7363eddc1beSBharat Bhushan memory_region_add_subregion(address_space_mem, MPC8544_CCSRBAR_BASE, 7373eddc1beSBharat Bhushan ccsr_addr_space); 738dffb1dc2SBharat Bhushan 73982fc73b6SScott Wood mpic = ppce500_init_mpic(params, ccsr_addr_space, irqs); 7401db09b84Saurel32 7411db09b84Saurel32 /* Serial */ 7422d48377aSBlue Swirl if (serial_hds[0]) { 7433eddc1beSBharat Bhushan serial_mm_init(ccsr_addr_space, MPC8544_SERIAL0_REGS_OFFSET, 744cdbb912aSAlexander Graf 0, mpic[42], 399193, 7452ff0c7c3SRichard Henderson serial_hds[0], DEVICE_BIG_ENDIAN); 7462d48377aSBlue Swirl } 7471db09b84Saurel32 7482d48377aSBlue Swirl if (serial_hds[1]) { 7493eddc1beSBharat Bhushan serial_mm_init(ccsr_addr_space, MPC8544_SERIAL1_REGS_OFFSET, 750cdbb912aSAlexander Graf 0, mpic[42], 399193, 75159de4f98SBharat Bhushan serial_hds[1], DEVICE_BIG_ENDIAN); 7522d48377aSBlue Swirl } 7531db09b84Saurel32 754b0fb8423SAlexander Graf /* General Utility device */ 755dffb1dc2SBharat Bhushan dev = qdev_create(NULL, "mpc8544-guts"); 756dffb1dc2SBharat Bhushan qdev_init_nofail(dev); 757dffb1dc2SBharat Bhushan s = SYS_BUS_DEVICE(dev); 7583eddc1beSBharat Bhushan memory_region_add_subregion(ccsr_addr_space, MPC8544_UTIL_OFFSET, 759dffb1dc2SBharat Bhushan sysbus_mmio_get_region(s, 0)); 760b0fb8423SAlexander Graf 7611db09b84Saurel32 /* PCI */ 762dffb1dc2SBharat Bhushan dev = qdev_create(NULL, "e500-pcihost"); 763492ec48dSAlexander Graf qdev_prop_set_uint32(dev, "first_slot", params->pci_first_slot); 7643016dca0SBharat Bhushan qdev_prop_set_uint32(dev, "first_pin_irq", pci_irq_nrs[0]); 765dffb1dc2SBharat Bhushan qdev_init_nofail(dev); 766dffb1dc2SBharat Bhushan s = SYS_BUS_DEVICE(dev); 767d575a6ceSBharat Bhushan for (i = 0; i < PCI_NUM_PINS; i++) { 768d575a6ceSBharat Bhushan sysbus_connect_irq(s, i, mpic[pci_irq_nrs[i]]); 769d575a6ceSBharat Bhushan } 770d575a6ceSBharat Bhushan 7713eddc1beSBharat Bhushan memory_region_add_subregion(ccsr_addr_space, MPC8544_PCI_REGS_OFFSET, 772dffb1dc2SBharat Bhushan sysbus_mmio_get_region(s, 0)); 773dffb1dc2SBharat Bhushan 774d461e3b9SAlexander Graf pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0"); 7751db09b84Saurel32 if (!pci_bus) 7761db09b84Saurel32 printf("couldn't create PCI controller!\n"); 7771db09b84Saurel32 7781356b98dSAndreas Färber sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, MPC8544_PCI_IO); 7791db09b84Saurel32 7801db09b84Saurel32 if (pci_bus) { 7811db09b84Saurel32 /* Register network interfaces. */ 7821db09b84Saurel32 for (i = 0; i < nb_nics; i++) { 78329b358f9SDavid Gibson pci_nic_init_nofail(&nd_table[i], pci_bus, "virtio", NULL); 7841db09b84Saurel32 } 7851db09b84Saurel32 } 7861db09b84Saurel32 7875c145dacSAlexander Graf /* Register spinning region */ 7885c145dacSAlexander Graf sysbus_create_simple("e500-spin", MPC8544_SPIN_BASE, NULL); 7895c145dacSAlexander Graf 7903812c71fSAlexander Graf if (cur_base < (32 * 1024 * 1024)) { 7913812c71fSAlexander Graf /* u-boot occupies memory up to 32MB, so load blobs above */ 7923812c71fSAlexander Graf cur_base = (32 * 1024 * 1024); 7933812c71fSAlexander Graf } 7943812c71fSAlexander Graf 795*b88e77f4SAlexander Graf if (params->has_mpc8xxx_gpio) { 796*b88e77f4SAlexander Graf dev = qdev_create(NULL, "mpc8xxx_gpio"); 797*b88e77f4SAlexander Graf s = SYS_BUS_DEVICE(dev); 798*b88e77f4SAlexander Graf qdev_init_nofail(dev); 799*b88e77f4SAlexander Graf sysbus_connect_irq(s, 0, mpic[MPC8XXX_GPIO_IRQ]); 800*b88e77f4SAlexander Graf memory_region_add_subregion(ccsr_addr_space, MPC8XXX_GPIO_OFFSET, 801*b88e77f4SAlexander Graf sysbus_mmio_get_region(s, 0)); 802*b88e77f4SAlexander Graf } 803*b88e77f4SAlexander Graf 8041db09b84Saurel32 /* Load kernel. */ 8053ef96221SMarcel Apfelbaum if (machine->kernel_filename) { 8063812c71fSAlexander Graf kernel_base = cur_base; 8073812c71fSAlexander Graf kernel_size = load_image_targphys(machine->kernel_filename, 8083812c71fSAlexander Graf cur_base, 8093812c71fSAlexander Graf ram_size - cur_base); 8101db09b84Saurel32 if (kernel_size < 0) { 8111db09b84Saurel32 fprintf(stderr, "qemu: could not load kernel '%s'\n", 8123ef96221SMarcel Apfelbaum machine->kernel_filename); 8131db09b84Saurel32 exit(1); 8141db09b84Saurel32 } 815528e536eSAlexander Graf 8163812c71fSAlexander Graf cur_base += kernel_size; 8171db09b84Saurel32 } 8181db09b84Saurel32 8191db09b84Saurel32 /* Load initrd. */ 8203ef96221SMarcel Apfelbaum if (machine->initrd_filename) { 821528e536eSAlexander Graf initrd_base = (cur_base + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK; 8223ef96221SMarcel Apfelbaum initrd_size = load_image_targphys(machine->initrd_filename, initrd_base, 823d7585251Spbrook ram_size - initrd_base); 8241db09b84Saurel32 8251db09b84Saurel32 if (initrd_size < 0) { 8261db09b84Saurel32 fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", 8273ef96221SMarcel Apfelbaum machine->initrd_filename); 8281db09b84Saurel32 exit(1); 8291db09b84Saurel32 } 830528e536eSAlexander Graf 831528e536eSAlexander Graf cur_base = initrd_base + initrd_size; 8321db09b84Saurel32 } 8331db09b84Saurel32 8343812c71fSAlexander Graf /* 8353812c71fSAlexander Graf * Smart firmware defaults ahead! 8363812c71fSAlexander Graf * 8373812c71fSAlexander Graf * We follow the following table to select which payload we execute. 8383812c71fSAlexander Graf * 8393812c71fSAlexander Graf * -kernel | -bios | payload 8403812c71fSAlexander Graf * ---------+-------+--------- 8413812c71fSAlexander Graf * N | Y | u-boot 8423812c71fSAlexander Graf * N | N | u-boot 8433812c71fSAlexander Graf * Y | Y | u-boot 8443812c71fSAlexander Graf * Y | N | kernel 8453812c71fSAlexander Graf * 8463812c71fSAlexander Graf * This ensures backwards compatibility with how we used to expose 8473812c71fSAlexander Graf * -kernel to users but allows them to run through u-boot as well. 8483812c71fSAlexander Graf */ 8493812c71fSAlexander Graf if (bios_name == NULL) { 8503ef96221SMarcel Apfelbaum if (machine->kernel_filename) { 8513812c71fSAlexander Graf bios_name = machine->kernel_filename; 8523812c71fSAlexander Graf } else { 8533812c71fSAlexander Graf bios_name = "u-boot.e500"; 8543812c71fSAlexander Graf } 8553812c71fSAlexander Graf } 8563812c71fSAlexander Graf filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); 8573812c71fSAlexander Graf 8583812c71fSAlexander Graf bios_size = load_elf(filename, NULL, NULL, &bios_entry, &loadaddr, NULL, 8593812c71fSAlexander Graf 1, ELF_MACHINE, 0); 8603812c71fSAlexander Graf if (bios_size < 0) { 8613812c71fSAlexander Graf /* 8623812c71fSAlexander Graf * Hrm. No ELF image? Try a uImage, maybe someone is giving us an 8633812c71fSAlexander Graf * ePAPR compliant kernel 8643812c71fSAlexander Graf */ 86525bda50aSMax Filippov kernel_size = load_uimage(filename, &bios_entry, &loadaddr, NULL, 86625bda50aSMax Filippov NULL, NULL); 8673812c71fSAlexander Graf if (kernel_size < 0) { 8683812c71fSAlexander Graf fprintf(stderr, "qemu: could not load firmware '%s'\n", filename); 8693812c71fSAlexander Graf exit(1); 8703812c71fSAlexander Graf } 8713812c71fSAlexander Graf } 8723812c71fSAlexander Graf 8733812c71fSAlexander Graf /* Reserve space for dtb */ 8743812c71fSAlexander Graf dt_base = (loadaddr + bios_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK; 8755c145dacSAlexander Graf 8763ef96221SMarcel Apfelbaum dt_size = ppce500_prep_device_tree(machine, params, dt_base, 877903585deSAlexander Graf initrd_base, initrd_size, 8783812c71fSAlexander Graf kernel_base, kernel_size); 879cba2026aSAlexander Graf if (dt_size < 0) { 8801db09b84Saurel32 fprintf(stderr, "couldn't load device tree\n"); 8811db09b84Saurel32 exit(1); 8821db09b84Saurel32 } 883b8dec144SAlexander Graf assert(dt_size < DTB_MAX_SIZE); 8841db09b84Saurel32 885e61c36d5SAlexander Graf boot_info = env->load_info; 8863812c71fSAlexander Graf boot_info->entry = bios_entry; 8873b989d49SAlexander Graf boot_info->dt_base = dt_base; 888cba2026aSAlexander Graf boot_info->dt_size = dt_size; 8891db09b84Saurel32 8903b989d49SAlexander Graf if (kvm_enabled()) { 8911db09b84Saurel32 kvmppc_init(); 8923b989d49SAlexander Graf } 8931db09b84Saurel32 } 8943eddc1beSBharat Bhushan 8953eddc1beSBharat Bhushan static int e500_ccsr_initfn(SysBusDevice *dev) 8963eddc1beSBharat Bhushan { 8973eddc1beSBharat Bhushan PPCE500CCSRState *ccsr; 8983eddc1beSBharat Bhushan 8993eddc1beSBharat Bhushan ccsr = CCSR(dev); 90040c5dce9SPaolo Bonzini memory_region_init(&ccsr->ccsr_space, OBJECT(ccsr), "e500-ccsr", 9013eddc1beSBharat Bhushan MPC8544_CCSRBAR_SIZE); 9023eddc1beSBharat Bhushan return 0; 9033eddc1beSBharat Bhushan } 9043eddc1beSBharat Bhushan 9053eddc1beSBharat Bhushan static void e500_ccsr_class_init(ObjectClass *klass, void *data) 9063eddc1beSBharat Bhushan { 9073eddc1beSBharat Bhushan SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); 9083eddc1beSBharat Bhushan k->init = e500_ccsr_initfn; 9093eddc1beSBharat Bhushan } 9103eddc1beSBharat Bhushan 9113eddc1beSBharat Bhushan static const TypeInfo e500_ccsr_info = { 9123eddc1beSBharat Bhushan .name = TYPE_CCSR, 9133eddc1beSBharat Bhushan .parent = TYPE_SYS_BUS_DEVICE, 9143eddc1beSBharat Bhushan .instance_size = sizeof(PPCE500CCSRState), 9153eddc1beSBharat Bhushan .class_init = e500_ccsr_class_init, 9163eddc1beSBharat Bhushan }; 9173eddc1beSBharat Bhushan 9183eddc1beSBharat Bhushan static void e500_register_types(void) 9193eddc1beSBharat Bhushan { 9203eddc1beSBharat Bhushan type_register_static(&e500_ccsr_info); 9213eddc1beSBharat Bhushan } 9223eddc1beSBharat Bhushan 9233eddc1beSBharat Bhushan type_init(e500_register_types) 924