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" 20*3eddc1beSBharat Bhushan #include "e500-ccsr.h" 211db09b84Saurel32 #include "net.h" 224a18e7c9SScott Wood #include "hw/hw.h" 23488cb996SGerd Hoffmann #include "hw/serial.h" 244a18e7c9SScott Wood #include "hw/pci.h" 254a18e7c9SScott Wood #include "hw/boards.h" 261db09b84Saurel32 #include "sysemu.h" 271db09b84Saurel32 #include "kvm.h" 281db09b84Saurel32 #include "kvm_ppc.h" 291db09b84Saurel32 #include "device_tree.h" 304a18e7c9SScott Wood #include "hw/openpic.h" 314a18e7c9SScott Wood #include "hw/ppc.h" 324a18e7c9SScott Wood #include "hw/loader.h" 33ca20cf32SBlue Swirl #include "elf.h" 344a18e7c9SScott Wood #include "hw/sysbus.h" 3539186d8aSRichard Henderson #include "exec-memory.h" 36cba2026aSAlexander Graf #include "host-utils.h" 371db09b84Saurel32 381db09b84Saurel32 #define BINARY_DEVICE_TREE_FILE "mpc8544ds.dtb" 391db09b84Saurel32 #define UIMAGE_LOAD_BASE 0 409dd5eba1SScott Wood #define DTC_LOAD_PAD 0x1800000 4175bb6589SLiu Yu #define DTC_PAD_MASK 0xFFFFF 4275bb6589SLiu Yu #define INITRD_LOAD_PAD 0x2000000 4375bb6589SLiu Yu #define INITRD_PAD_MASK 0xFFFFFF 441db09b84Saurel32 451db09b84Saurel32 #define RAM_SIZES_ALIGN (64UL << 20) 461db09b84Saurel32 47b3305981SScott Wood /* TODO: parameterize */ 48ed2bc496SAlexander Graf #define MPC8544_CCSRBAR_BASE 0xE0000000ULL 49ed2bc496SAlexander Graf #define MPC8544_CCSRBAR_SIZE 0x00100000ULL 50dffb1dc2SBharat Bhushan #define MPC8544_MPIC_REGS_OFFSET 0x40000ULL 51dffb1dc2SBharat Bhushan #define MPC8544_SERIAL0_REGS_OFFSET 0x4500ULL 52dffb1dc2SBharat Bhushan #define MPC8544_SERIAL1_REGS_OFFSET 0x4600ULL 53dffb1dc2SBharat Bhushan #define MPC8544_PCI_REGS_OFFSET 0x8000ULL 54dffb1dc2SBharat Bhushan #define MPC8544_PCI_REGS_BASE (MPC8544_CCSRBAR_BASE + \ 55dffb1dc2SBharat Bhushan MPC8544_PCI_REGS_OFFSET) 56ed2bc496SAlexander Graf #define MPC8544_PCI_REGS_SIZE 0x1000ULL 57ed2bc496SAlexander Graf #define MPC8544_PCI_IO 0xE1000000ULL 58dffb1dc2SBharat Bhushan #define MPC8544_UTIL_OFFSET 0xe0000ULL 59ed2bc496SAlexander Graf #define MPC8544_SPIN_BASE 0xEF000000ULL 601db09b84Saurel32 613b989d49SAlexander Graf struct boot_info 623b989d49SAlexander Graf { 633b989d49SAlexander Graf uint32_t dt_base; 64cba2026aSAlexander Graf uint32_t dt_size; 653b989d49SAlexander Graf uint32_t entry; 663b989d49SAlexander Graf }; 673b989d49SAlexander Graf 680dbc0798SAlexander Graf static void pci_map_create(void *fdt, uint32_t *pci_map, uint32_t mpic) 690dbc0798SAlexander Graf { 700dbc0798SAlexander Graf int i; 710dbc0798SAlexander Graf const uint32_t tmp[] = { 720dbc0798SAlexander Graf /* IDSEL 0x11 J17 Slot 1 */ 737e99826cSAlexander Graf 0x8800, 0x0, 0x0, 0x1, mpic, 0x2, 0x1, 747e99826cSAlexander Graf 0x8800, 0x0, 0x0, 0x2, mpic, 0x3, 0x1, 757e99826cSAlexander Graf 0x8800, 0x0, 0x0, 0x3, mpic, 0x4, 0x1, 767e99826cSAlexander Graf 0x8800, 0x0, 0x0, 0x4, mpic, 0x1, 0x1, 770dbc0798SAlexander Graf 780dbc0798SAlexander Graf /* IDSEL 0x12 J16 Slot 2 */ 797e99826cSAlexander Graf 0x9000, 0x0, 0x0, 0x1, mpic, 0x3, 0x1, 807e99826cSAlexander Graf 0x9000, 0x0, 0x0, 0x2, mpic, 0x4, 0x1, 817e99826cSAlexander Graf 0x9000, 0x0, 0x0, 0x3, mpic, 0x2, 0x1, 827e99826cSAlexander Graf 0x9000, 0x0, 0x0, 0x4, mpic, 0x1, 0x1, 830dbc0798SAlexander Graf }; 847e99826cSAlexander Graf for (i = 0; i < (7 * 8); i++) { 850dbc0798SAlexander Graf pci_map[i] = cpu_to_be32(tmp[i]); 860dbc0798SAlexander Graf } 870dbc0798SAlexander Graf } 880dbc0798SAlexander Graf 89a053a7ceSAlexander Graf static void dt_serial_create(void *fdt, unsigned long long offset, 90a053a7ceSAlexander Graf const char *soc, const char *mpic, 91a053a7ceSAlexander Graf const char *alias, int idx, bool defcon) 92a053a7ceSAlexander Graf { 93a053a7ceSAlexander Graf char ser[128]; 94a053a7ceSAlexander Graf 95a053a7ceSAlexander Graf snprintf(ser, sizeof(ser), "%s/serial@%llx", soc, offset); 96a053a7ceSAlexander Graf qemu_devtree_add_subnode(fdt, ser); 97a053a7ceSAlexander Graf qemu_devtree_setprop_string(fdt, ser, "device_type", "serial"); 98a053a7ceSAlexander Graf qemu_devtree_setprop_string(fdt, ser, "compatible", "ns16550"); 99a053a7ceSAlexander Graf qemu_devtree_setprop_cells(fdt, ser, "reg", offset, 0x100); 100a053a7ceSAlexander Graf qemu_devtree_setprop_cell(fdt, ser, "cell-index", idx); 101a053a7ceSAlexander Graf qemu_devtree_setprop_cell(fdt, ser, "clock-frequency", 0); 1027e99826cSAlexander Graf qemu_devtree_setprop_cells(fdt, ser, "interrupts", 42, 2); 103a053a7ceSAlexander Graf qemu_devtree_setprop_phandle(fdt, ser, "interrupt-parent", mpic); 104a053a7ceSAlexander Graf qemu_devtree_setprop_string(fdt, "/aliases", alias, ser); 105a053a7ceSAlexander Graf 106a053a7ceSAlexander Graf if (defcon) { 107a053a7ceSAlexander Graf qemu_devtree_setprop_string(fdt, "/chosen", "linux,stdout-path", ser); 108a053a7ceSAlexander Graf } 109a053a7ceSAlexander Graf } 110a053a7ceSAlexander Graf 111b3305981SScott Wood static int ppce500_load_device_tree(CPUPPCState *env, 112e6eaabebSScott Wood PPCE500Params *params, 113a8170e5eSAvi Kivity hwaddr addr, 114a8170e5eSAvi Kivity hwaddr initrd_base, 115a8170e5eSAvi Kivity hwaddr initrd_size) 1161db09b84Saurel32 { 117dbf916d8SAurelien Jarno int ret = -1; 118e6eaabebSScott Wood uint64_t mem_reg_property[] = { 0, cpu_to_be64(params->ram_size) }; 1197ec632b4Spbrook int fdt_size; 120dbf916d8SAurelien Jarno void *fdt; 1215de6b46dSAlexander Graf uint8_t hypercall[16]; 122911d6e7aSAlexander Graf uint32_t clock_freq = 400000000; 123911d6e7aSAlexander Graf uint32_t tb_freq = 400000000; 124621d05e3SAlexander Graf int i; 125e6eaabebSScott Wood const char *toplevel_compat = NULL; /* user override */ 126ebb9518aSAlexander Graf char compatible_sb[] = "fsl,mpc8544-immr\0simple-bus"; 1275da96624SAlexander Graf char soc[128]; 12819ac9deaSAlexander Graf char mpic[128]; 12919ac9deaSAlexander Graf uint32_t mpic_ph; 130f5038483SAlexander Graf char gutil[128]; 1310dbc0798SAlexander Graf char pci[128]; 1327e99826cSAlexander Graf uint32_t pci_map[7 * 8]; 1333627757eSAlexander Graf uint32_t pci_ranges[14] = 1343627757eSAlexander Graf { 1353627757eSAlexander Graf 0x2000000, 0x0, 0xc0000000, 1363627757eSAlexander Graf 0x0, 0xc0000000, 1373627757eSAlexander Graf 0x0, 0x20000000, 1383627757eSAlexander Graf 1393627757eSAlexander Graf 0x1000000, 0x0, 0x0, 1403627757eSAlexander Graf 0x0, 0xe1000000, 1413627757eSAlexander Graf 0x0, 0x10000, 1423627757eSAlexander Graf }; 14325b42708SAlexander Graf QemuOpts *machine_opts; 144d1b93565SAlexander Graf const char *dtb_file = NULL; 145d1b93565SAlexander Graf 146d1b93565SAlexander Graf machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0); 147d1b93565SAlexander Graf if (machine_opts) { 148d1b93565SAlexander Graf dtb_file = qemu_opt_get(machine_opts, "dtb"); 149e6eaabebSScott Wood toplevel_compat = qemu_opt_get(machine_opts, "dt_compatible"); 150d1b93565SAlexander Graf } 151d1b93565SAlexander Graf 152d1b93565SAlexander Graf if (dtb_file) { 153d1b93565SAlexander Graf char *filename; 154d1b93565SAlexander Graf filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_file); 155d1b93565SAlexander Graf if (!filename) { 156d1b93565SAlexander Graf goto out; 157d1b93565SAlexander Graf } 158d1b93565SAlexander Graf 159d1b93565SAlexander Graf fdt = load_device_tree(filename, &fdt_size); 160d1b93565SAlexander Graf if (!fdt) { 161d1b93565SAlexander Graf goto out; 162d1b93565SAlexander Graf } 163d1b93565SAlexander Graf goto done; 164d1b93565SAlexander Graf } 1651db09b84Saurel32 1662636fcb6SAlexander Graf fdt = create_device_tree(&fdt_size); 1675cea8590SPaul Brook if (fdt == NULL) { 1685cea8590SPaul Brook goto out; 1695cea8590SPaul Brook } 1701db09b84Saurel32 1711db09b84Saurel32 /* Manipulate device tree in memory. */ 1723627757eSAlexander Graf qemu_devtree_setprop_cell(fdt, "/", "#address-cells", 2); 1733627757eSAlexander Graf qemu_devtree_setprop_cell(fdt, "/", "#size-cells", 2); 17451b852b7SAlexander Graf 175dd0bcfcaSAlexander Graf qemu_devtree_add_subnode(fdt, "/memory"); 176dd0bcfcaSAlexander Graf qemu_devtree_setprop_string(fdt, "/memory", "device_type", "memory"); 177dd0bcfcaSAlexander Graf qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property, 1781db09b84Saurel32 sizeof(mem_reg_property)); 1791db09b84Saurel32 180f5231aafSAlexander Graf qemu_devtree_add_subnode(fdt, "/chosen"); 1813b989d49SAlexander Graf if (initrd_size) { 1821db09b84Saurel32 ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start", 1831db09b84Saurel32 initrd_base); 1843b989d49SAlexander Graf if (ret < 0) { 1851db09b84Saurel32 fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n"); 1863b989d49SAlexander Graf } 1871db09b84Saurel32 1881db09b84Saurel32 ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end", 1891db09b84Saurel32 (initrd_base + initrd_size)); 1903b989d49SAlexander Graf if (ret < 0) { 1911db09b84Saurel32 fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n"); 1923b989d49SAlexander Graf } 1933b989d49SAlexander Graf } 1941db09b84Saurel32 1951db09b84Saurel32 ret = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", 196e6eaabebSScott Wood params->kernel_cmdline); 1971db09b84Saurel32 if (ret < 0) 1981db09b84Saurel32 fprintf(stderr, "couldn't set /chosen/bootargs\n"); 1991db09b84Saurel32 2001db09b84Saurel32 if (kvm_enabled()) { 201911d6e7aSAlexander Graf /* Read out host's frequencies */ 202911d6e7aSAlexander Graf clock_freq = kvmppc_get_clockfreq(); 203911d6e7aSAlexander Graf tb_freq = kvmppc_get_tbfreq(); 2045de6b46dSAlexander Graf 2055de6b46dSAlexander Graf /* indicate KVM hypercall interface */ 206d50f71a5SAlexander Graf qemu_devtree_add_subnode(fdt, "/hypervisor"); 2075de6b46dSAlexander Graf qemu_devtree_setprop_string(fdt, "/hypervisor", "compatible", 2085de6b46dSAlexander Graf "linux,kvm"); 2095de6b46dSAlexander Graf kvmppc_get_hypercall(env, hypercall, sizeof(hypercall)); 2105de6b46dSAlexander Graf qemu_devtree_setprop(fdt, "/hypervisor", "hcall-instructions", 2115de6b46dSAlexander Graf hypercall, sizeof(hypercall)); 2121db09b84Saurel32 } 2131db09b84Saurel32 214625e665bSAlexander Graf /* Create CPU nodes */ 215625e665bSAlexander Graf qemu_devtree_add_subnode(fdt, "/cpus"); 216625e665bSAlexander Graf qemu_devtree_setprop_cell(fdt, "/cpus", "#address-cells", 1); 217625e665bSAlexander Graf qemu_devtree_setprop_cell(fdt, "/cpus", "#size-cells", 0); 218625e665bSAlexander Graf 2191e3debf0SAlexander Graf /* We need to generate the cpu nodes in reverse order, so Linux can pick 2201e3debf0SAlexander Graf the first node as boot node and be happy */ 2211e3debf0SAlexander Graf for (i = smp_cpus - 1; i >= 0; i--) { 222621d05e3SAlexander Graf char cpu_name[128]; 2231d2e5c52SAlexander Graf uint64_t cpu_release_addr = MPC8544_SPIN_BASE + (i * 0x20); 22410f25a46SAlexander Graf 2251e3debf0SAlexander Graf for (env = first_cpu; env != NULL; env = env->next_cpu) { 2261e3debf0SAlexander Graf if (env->cpu_index == i) { 2271e3debf0SAlexander Graf break; 2281e3debf0SAlexander Graf } 229621d05e3SAlexander Graf } 230911d6e7aSAlexander Graf 2311e3debf0SAlexander Graf if (!env) { 2321e3debf0SAlexander Graf continue; 2331e3debf0SAlexander Graf } 2341e3debf0SAlexander Graf 2351e3debf0SAlexander Graf snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x", env->cpu_index); 2361e3debf0SAlexander Graf qemu_devtree_add_subnode(fdt, cpu_name); 2371e3debf0SAlexander Graf qemu_devtree_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq); 2381e3debf0SAlexander Graf qemu_devtree_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq); 2391e3debf0SAlexander Graf qemu_devtree_setprop_string(fdt, cpu_name, "device_type", "cpu"); 2401e3debf0SAlexander Graf qemu_devtree_setprop_cell(fdt, cpu_name, "reg", env->cpu_index); 2411e3debf0SAlexander Graf qemu_devtree_setprop_cell(fdt, cpu_name, "d-cache-line-size", 2421e3debf0SAlexander Graf env->dcache_line_size); 2431e3debf0SAlexander Graf qemu_devtree_setprop_cell(fdt, cpu_name, "i-cache-line-size", 2441e3debf0SAlexander Graf env->icache_line_size); 2451e3debf0SAlexander Graf qemu_devtree_setprop_cell(fdt, cpu_name, "d-cache-size", 0x8000); 2461e3debf0SAlexander Graf qemu_devtree_setprop_cell(fdt, cpu_name, "i-cache-size", 0x8000); 2471e3debf0SAlexander Graf qemu_devtree_setprop_cell(fdt, cpu_name, "bus-frequency", 0); 2481e3debf0SAlexander Graf if (env->cpu_index) { 2491e3debf0SAlexander Graf qemu_devtree_setprop_string(fdt, cpu_name, "status", "disabled"); 2501e3debf0SAlexander Graf qemu_devtree_setprop_string(fdt, cpu_name, "enable-method", "spin-table"); 2511d2e5c52SAlexander Graf qemu_devtree_setprop_u64(fdt, cpu_name, "cpu-release-addr", 2521d2e5c52SAlexander Graf cpu_release_addr); 2531e3debf0SAlexander Graf } else { 2541e3debf0SAlexander Graf qemu_devtree_setprop_string(fdt, cpu_name, "status", "okay"); 2551e3debf0SAlexander Graf } 2561db09b84Saurel32 } 2571db09b84Saurel32 2580cfc6e8dSAlexander Graf qemu_devtree_add_subnode(fdt, "/aliases"); 2595da96624SAlexander Graf /* XXX These should go into their respective devices' code */ 260ed2bc496SAlexander Graf snprintf(soc, sizeof(soc), "/soc@%llx", MPC8544_CCSRBAR_BASE); 2615da96624SAlexander Graf qemu_devtree_add_subnode(fdt, soc); 2625da96624SAlexander Graf qemu_devtree_setprop_string(fdt, soc, "device_type", "soc"); 263ebb9518aSAlexander Graf qemu_devtree_setprop(fdt, soc, "compatible", compatible_sb, 264ebb9518aSAlexander Graf sizeof(compatible_sb)); 2655da96624SAlexander Graf qemu_devtree_setprop_cell(fdt, soc, "#address-cells", 1); 2665da96624SAlexander Graf qemu_devtree_setprop_cell(fdt, soc, "#size-cells", 1); 2673627757eSAlexander Graf qemu_devtree_setprop_cells(fdt, soc, "ranges", 0x0, 2683627757eSAlexander Graf MPC8544_CCSRBAR_BASE >> 32, MPC8544_CCSRBAR_BASE, 2695da96624SAlexander Graf MPC8544_CCSRBAR_SIZE); 2705da96624SAlexander Graf /* XXX should contain a reasonable value */ 2715da96624SAlexander Graf qemu_devtree_setprop_cell(fdt, soc, "bus-frequency", 0); 2725da96624SAlexander Graf 273dffb1dc2SBharat Bhushan snprintf(mpic, sizeof(mpic), "%s/pic@%llx", soc, MPC8544_MPIC_REGS_OFFSET); 27419ac9deaSAlexander Graf qemu_devtree_add_subnode(fdt, mpic); 27519ac9deaSAlexander Graf qemu_devtree_setprop_string(fdt, mpic, "device_type", "open-pic"); 2767e99826cSAlexander Graf qemu_devtree_setprop_string(fdt, mpic, "compatible", "chrp,open-pic"); 277dffb1dc2SBharat Bhushan qemu_devtree_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_OFFSET, 278dffb1dc2SBharat Bhushan 0x40000); 27919ac9deaSAlexander Graf qemu_devtree_setprop_cell(fdt, mpic, "#address-cells", 0); 2807e99826cSAlexander Graf qemu_devtree_setprop_cell(fdt, mpic, "#interrupt-cells", 2); 28119ac9deaSAlexander Graf mpic_ph = qemu_devtree_alloc_phandle(fdt); 28219ac9deaSAlexander Graf qemu_devtree_setprop_cell(fdt, mpic, "phandle", mpic_ph); 28319ac9deaSAlexander Graf qemu_devtree_setprop_cell(fdt, mpic, "linux,phandle", mpic_ph); 28419ac9deaSAlexander Graf qemu_devtree_setprop(fdt, mpic, "interrupt-controller", NULL, 0); 28519ac9deaSAlexander Graf 2860cfc6e8dSAlexander Graf /* 2870cfc6e8dSAlexander Graf * We have to generate ser1 first, because Linux takes the first 2880cfc6e8dSAlexander Graf * device it finds in the dt as serial output device. And we generate 2890cfc6e8dSAlexander Graf * devices in reverse order to the dt. 2900cfc6e8dSAlexander Graf */ 291dffb1dc2SBharat Bhushan dt_serial_create(fdt, MPC8544_SERIAL1_REGS_OFFSET, 292a053a7ceSAlexander Graf soc, mpic, "serial1", 1, false); 293dffb1dc2SBharat Bhushan dt_serial_create(fdt, MPC8544_SERIAL0_REGS_OFFSET, 294a053a7ceSAlexander Graf soc, mpic, "serial0", 0, true); 2950cfc6e8dSAlexander Graf 296ed2bc496SAlexander Graf snprintf(gutil, sizeof(gutil), "%s/global-utilities@%llx", soc, 297dffb1dc2SBharat Bhushan MPC8544_UTIL_OFFSET); 298f5038483SAlexander Graf qemu_devtree_add_subnode(fdt, gutil); 299f5038483SAlexander Graf qemu_devtree_setprop_string(fdt, gutil, "compatible", "fsl,mpc8544-guts"); 300dffb1dc2SBharat Bhushan qemu_devtree_setprop_cells(fdt, gutil, "reg", MPC8544_UTIL_OFFSET, 0x1000); 301f5038483SAlexander Graf qemu_devtree_setprop(fdt, gutil, "fsl,has-rstcr", NULL, 0); 302f5038483SAlexander Graf 303ed2bc496SAlexander Graf snprintf(pci, sizeof(pci), "/pci@%llx", MPC8544_PCI_REGS_BASE); 3040dbc0798SAlexander Graf qemu_devtree_add_subnode(fdt, pci); 3050dbc0798SAlexander Graf qemu_devtree_setprop_cell(fdt, pci, "cell-index", 0); 3060dbc0798SAlexander Graf qemu_devtree_setprop_string(fdt, pci, "compatible", "fsl,mpc8540-pci"); 3070dbc0798SAlexander Graf qemu_devtree_setprop_string(fdt, pci, "device_type", "pci"); 3080dbc0798SAlexander Graf qemu_devtree_setprop_cells(fdt, pci, "interrupt-map-mask", 0xf800, 0x0, 3090dbc0798SAlexander Graf 0x0, 0x7); 3100dbc0798SAlexander Graf pci_map_create(fdt, pci_map, qemu_devtree_get_phandle(fdt, mpic)); 3110dbc0798SAlexander Graf qemu_devtree_setprop(fdt, pci, "interrupt-map", pci_map, sizeof(pci_map)); 3120dbc0798SAlexander Graf qemu_devtree_setprop_phandle(fdt, pci, "interrupt-parent", mpic); 3137e99826cSAlexander Graf qemu_devtree_setprop_cells(fdt, pci, "interrupts", 24, 2); 3140dbc0798SAlexander Graf qemu_devtree_setprop_cells(fdt, pci, "bus-range", 0, 255); 3153627757eSAlexander Graf for (i = 0; i < 14; i++) { 3160dbc0798SAlexander Graf pci_ranges[i] = cpu_to_be32(pci_ranges[i]); 3170dbc0798SAlexander Graf } 3180dbc0798SAlexander Graf qemu_devtree_setprop(fdt, pci, "ranges", pci_ranges, sizeof(pci_ranges)); 3193627757eSAlexander Graf qemu_devtree_setprop_cells(fdt, pci, "reg", MPC8544_PCI_REGS_BASE >> 32, 3203627757eSAlexander Graf MPC8544_PCI_REGS_BASE, 0, 0x1000); 3210dbc0798SAlexander Graf qemu_devtree_setprop_cell(fdt, pci, "clock-frequency", 66666666); 3220dbc0798SAlexander Graf qemu_devtree_setprop_cell(fdt, pci, "#interrupt-cells", 1); 3230dbc0798SAlexander Graf qemu_devtree_setprop_cell(fdt, pci, "#size-cells", 2); 3240dbc0798SAlexander Graf qemu_devtree_setprop_cell(fdt, pci, "#address-cells", 3); 3250dbc0798SAlexander Graf qemu_devtree_setprop_string(fdt, "/aliases", "pci0", pci); 3260dbc0798SAlexander Graf 327e6eaabebSScott Wood params->fixup_devtree(params, fdt); 328e6eaabebSScott Wood 329e6eaabebSScott Wood if (toplevel_compat) { 330e6eaabebSScott Wood qemu_devtree_setprop(fdt, "/", "compatible", toplevel_compat, 331e6eaabebSScott Wood strlen(toplevel_compat) + 1); 332e6eaabebSScott Wood } 333e6eaabebSScott Wood 334d1b93565SAlexander Graf done: 33571193433SAlexander Graf qemu_devtree_dumpdtb(fdt, fdt_size); 33604088adbSLiu Yu ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr); 337cba2026aSAlexander Graf if (ret < 0) { 338cba2026aSAlexander Graf goto out; 339cba2026aSAlexander Graf } 3407267c094SAnthony Liguori g_free(fdt); 341cba2026aSAlexander Graf ret = fdt_size; 3427ec632b4Spbrook 3431db09b84Saurel32 out: 3441db09b84Saurel32 34504088adbSLiu Yu return ret; 3461db09b84Saurel32 } 3471db09b84Saurel32 348cba2026aSAlexander Graf /* Create -kernel TLB entries for BookE. */ 349a8170e5eSAvi Kivity static inline hwaddr booke206_page_size_to_tlb(uint64_t size) 350d1e256feSAlexander Graf { 351cba2026aSAlexander Graf return 63 - clz64(size >> 10); 352d1e256feSAlexander Graf } 353d1e256feSAlexander Graf 354cba2026aSAlexander Graf static void mmubooke_create_initial_mapping(CPUPPCState *env) 3553b989d49SAlexander Graf { 356cba2026aSAlexander Graf struct boot_info *bi = env->load_info; 357d1e256feSAlexander Graf ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0); 358a8170e5eSAvi Kivity hwaddr size, dt_end; 359cba2026aSAlexander Graf int ps; 3603b989d49SAlexander Graf 361cba2026aSAlexander Graf /* Our initial TLB entry needs to cover everything from 0 to 362cba2026aSAlexander Graf the device tree top */ 363cba2026aSAlexander Graf dt_end = bi->dt_base + bi->dt_size; 364cba2026aSAlexander Graf ps = booke206_page_size_to_tlb(dt_end) + 1; 365fb37c302SAlexander Graf if (ps & 1) { 366fb37c302SAlexander Graf /* e500v2 can only do even TLB size bits */ 367fb37c302SAlexander Graf ps++; 368fb37c302SAlexander Graf } 369cba2026aSAlexander Graf size = (ps << MAS1_TSIZE_SHIFT); 370d1e256feSAlexander Graf tlb->mas1 = MAS1_VALID | size; 371cba2026aSAlexander Graf tlb->mas2 = 0; 372cba2026aSAlexander Graf tlb->mas7_3 = 0; 373d1e256feSAlexander Graf tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX; 37493dd5e85SScott Wood 37593dd5e85SScott Wood env->tlb_dirty = true; 3763b989d49SAlexander Graf } 3773b989d49SAlexander Graf 378b3305981SScott Wood static void ppce500_cpu_reset_sec(void *opaque) 3795c145dacSAlexander Graf { 38038f92da6SAndreas Färber PowerPCCPU *cpu = opaque; 38138f92da6SAndreas Färber CPUPPCState *env = &cpu->env; 3825c145dacSAlexander Graf 38338f92da6SAndreas Färber cpu_reset(CPU(cpu)); 3845c145dacSAlexander Graf 3855c145dacSAlexander Graf /* Secondary CPU starts in halted state for now. Needs to change when 3865c145dacSAlexander Graf implementing non-kernel boot. */ 3875c145dacSAlexander Graf env->halted = 1; 3885c145dacSAlexander Graf env->exception_index = EXCP_HLT; 3893b989d49SAlexander Graf } 3903b989d49SAlexander Graf 391b3305981SScott Wood static void ppce500_cpu_reset(void *opaque) 3923b989d49SAlexander Graf { 39338f92da6SAndreas Färber PowerPCCPU *cpu = opaque; 39438f92da6SAndreas Färber CPUPPCState *env = &cpu->env; 3953b989d49SAlexander Graf struct boot_info *bi = env->load_info; 3963b989d49SAlexander Graf 39738f92da6SAndreas Färber cpu_reset(CPU(cpu)); 3983b989d49SAlexander Graf 3993b989d49SAlexander Graf /* Set initial guest state. */ 4005c145dacSAlexander Graf env->halted = 0; 4013b989d49SAlexander Graf env->gpr[1] = (16<<20) - 8; 4023b989d49SAlexander Graf env->gpr[3] = bi->dt_base; 4033b989d49SAlexander Graf env->nip = bi->entry; 404cba2026aSAlexander Graf mmubooke_create_initial_mapping(env); 4053b989d49SAlexander Graf } 4063b989d49SAlexander Graf 407e6eaabebSScott Wood void ppce500_init(PPCE500Params *params) 4081db09b84Saurel32 { 40939186d8aSRichard Henderson MemoryRegion *address_space_mem = get_system_memory(); 4102646c133SAvi Kivity MemoryRegion *ram = g_new(MemoryRegion, 1); 4111db09b84Saurel32 PCIBus *pci_bus; 412e2684c0bSAndreas Färber CPUPPCState *env = NULL; 4131db09b84Saurel32 uint64_t elf_entry; 4141db09b84Saurel32 uint64_t elf_lowaddr; 415a8170e5eSAvi Kivity hwaddr entry=0; 416a8170e5eSAvi Kivity hwaddr loadaddr=UIMAGE_LOAD_BASE; 4171db09b84Saurel32 target_long kernel_size=0; 41875bb6589SLiu Yu target_ulong dt_base = 0; 41975bb6589SLiu Yu target_ulong initrd_base = 0; 4201db09b84Saurel32 target_long initrd_size=0; 4211db09b84Saurel32 int i=0; 4221db09b84Saurel32 unsigned int pci_irq_nrs[4] = {1, 2, 3, 4}; 423a915249fSAlexander Graf qemu_irq **irqs, *mpic; 424be13cc7aSAlexander Graf DeviceState *dev; 425e2684c0bSAndreas Färber CPUPPCState *firstenv = NULL; 426*3eddc1beSBharat Bhushan MemoryRegion *ccsr_addr_space; 427dffb1dc2SBharat Bhushan SysBusDevice *s; 428*3eddc1beSBharat Bhushan PPCE500CCSRState *ccsr; 4291db09b84Saurel32 430e61c36d5SAlexander Graf /* Setup CPUs */ 431e6eaabebSScott Wood if (params->cpu_model == NULL) { 432e6eaabebSScott Wood params->cpu_model = "e500v2_v30"; 433ef250db6SAlexander Graf } 434ef250db6SAlexander Graf 435a915249fSAlexander Graf irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *)); 436a915249fSAlexander Graf irqs[0] = g_malloc0(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB); 437e61c36d5SAlexander Graf for (i = 0; i < smp_cpus; i++) { 438397b457dSAndreas Färber PowerPCCPU *cpu; 439e61c36d5SAlexander Graf qemu_irq *input; 440397b457dSAndreas Färber 441e6eaabebSScott Wood cpu = cpu_ppc_init(params->cpu_model); 442397b457dSAndreas Färber if (cpu == NULL) { 4431db09b84Saurel32 fprintf(stderr, "Unable to initialize CPU!\n"); 4441db09b84Saurel32 exit(1); 4451db09b84Saurel32 } 446397b457dSAndreas Färber env = &cpu->env; 4471db09b84Saurel32 448e61c36d5SAlexander Graf if (!firstenv) { 449e61c36d5SAlexander Graf firstenv = env; 450e61c36d5SAlexander Graf } 451e61c36d5SAlexander Graf 452a915249fSAlexander Graf irqs[i] = irqs[0] + (i * OPENPIC_OUTPUT_NB); 453a915249fSAlexander Graf input = (qemu_irq *)env->irq_inputs; 454a915249fSAlexander Graf irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT]; 455a915249fSAlexander Graf irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT]; 456e61c36d5SAlexander Graf env->spr[SPR_BOOKE_PIR] = env->cpu_index = i; 457dffb1dc2SBharat Bhushan env->mpic_cpu_base = MPC8544_CCSRBAR_BASE + 458dffb1dc2SBharat Bhushan MPC8544_MPIC_REGS_OFFSET + 0x20000; 459e61c36d5SAlexander Graf 460ddd1055bSFabien Chouteau ppc_booke_timers_init(env, 400000000, PPC_TIMER_E500); 4613b989d49SAlexander Graf 4623b989d49SAlexander Graf /* Register reset handler */ 4635c145dacSAlexander Graf if (!i) { 4645c145dacSAlexander Graf /* Primary CPU */ 4655c145dacSAlexander Graf struct boot_info *boot_info; 466e61c36d5SAlexander Graf boot_info = g_malloc0(sizeof(struct boot_info)); 467b3305981SScott Wood qemu_register_reset(ppce500_cpu_reset, cpu); 468e61c36d5SAlexander Graf env->load_info = boot_info; 4695c145dacSAlexander Graf } else { 4705c145dacSAlexander Graf /* Secondary CPUs */ 471b3305981SScott Wood qemu_register_reset(ppce500_cpu_reset_sec, cpu); 4725c145dacSAlexander Graf } 473e61c36d5SAlexander Graf } 474e61c36d5SAlexander Graf 475e61c36d5SAlexander Graf env = firstenv; 4763b989d49SAlexander Graf 4771db09b84Saurel32 /* Fixup Memory size on a alignment boundary */ 4781db09b84Saurel32 ram_size &= ~(RAM_SIZES_ALIGN - 1); 4791db09b84Saurel32 4801db09b84Saurel32 /* Register Memory */ 481c5705a77SAvi Kivity memory_region_init_ram(ram, "mpc8544ds.ram", ram_size); 482c5705a77SAvi Kivity vmstate_register_ram_global(ram); 4832646c133SAvi Kivity memory_region_add_subregion(address_space_mem, 0, ram); 4841db09b84Saurel32 485*3eddc1beSBharat Bhushan dev = qdev_create(NULL, "e500-ccsr"); 486*3eddc1beSBharat Bhushan object_property_add_child(qdev_get_machine(), "e500-ccsr", 487*3eddc1beSBharat Bhushan OBJECT(dev), NULL); 488*3eddc1beSBharat Bhushan qdev_init_nofail(dev); 489*3eddc1beSBharat Bhushan ccsr = CCSR(dev); 490*3eddc1beSBharat Bhushan ccsr_addr_space = &ccsr->ccsr_space; 491*3eddc1beSBharat Bhushan memory_region_add_subregion(address_space_mem, MPC8544_CCSRBAR_BASE, 492*3eddc1beSBharat Bhushan ccsr_addr_space); 493dffb1dc2SBharat Bhushan 4941db09b84Saurel32 /* MPIC */ 495*3eddc1beSBharat Bhushan mpic = mpic_init(ccsr_addr_space, MPC8544_MPIC_REGS_OFFSET, 496df2921d3SAvi Kivity smp_cpus, irqs, NULL); 497a915249fSAlexander Graf 498a915249fSAlexander Graf if (!mpic) { 499a915249fSAlexander Graf cpu_abort(env, "MPIC failed to initialize\n"); 500a915249fSAlexander Graf } 5011db09b84Saurel32 5021db09b84Saurel32 /* Serial */ 5032d48377aSBlue Swirl if (serial_hds[0]) { 504*3eddc1beSBharat Bhushan serial_mm_init(ccsr_addr_space, MPC8544_SERIAL0_REGS_OFFSET, 5051db09b84Saurel32 0, mpic[12+26], 399193, 5062ff0c7c3SRichard Henderson serial_hds[0], DEVICE_BIG_ENDIAN); 5072d48377aSBlue Swirl } 5081db09b84Saurel32 5092d48377aSBlue Swirl if (serial_hds[1]) { 510*3eddc1beSBharat Bhushan serial_mm_init(ccsr_addr_space, MPC8544_SERIAL1_REGS_OFFSET, 5111db09b84Saurel32 0, mpic[12+26], 399193, 51259de4f98SBharat Bhushan serial_hds[1], DEVICE_BIG_ENDIAN); 5132d48377aSBlue Swirl } 5141db09b84Saurel32 515b0fb8423SAlexander Graf /* General Utility device */ 516dffb1dc2SBharat Bhushan dev = qdev_create(NULL, "mpc8544-guts"); 517dffb1dc2SBharat Bhushan qdev_init_nofail(dev); 518dffb1dc2SBharat Bhushan s = SYS_BUS_DEVICE(dev); 519*3eddc1beSBharat Bhushan memory_region_add_subregion(ccsr_addr_space, MPC8544_UTIL_OFFSET, 520dffb1dc2SBharat Bhushan sysbus_mmio_get_region(s, 0)); 521b0fb8423SAlexander Graf 5221db09b84Saurel32 /* PCI */ 523dffb1dc2SBharat Bhushan dev = qdev_create(NULL, "e500-pcihost"); 524dffb1dc2SBharat Bhushan qdev_init_nofail(dev); 525dffb1dc2SBharat Bhushan s = SYS_BUS_DEVICE(dev); 526dffb1dc2SBharat Bhushan sysbus_connect_irq(s, 0, mpic[pci_irq_nrs[0]]); 527dffb1dc2SBharat Bhushan sysbus_connect_irq(s, 1, mpic[pci_irq_nrs[1]]); 528dffb1dc2SBharat Bhushan sysbus_connect_irq(s, 2, mpic[pci_irq_nrs[2]]); 529dffb1dc2SBharat Bhushan sysbus_connect_irq(s, 3, mpic[pci_irq_nrs[3]]); 530*3eddc1beSBharat Bhushan memory_region_add_subregion(ccsr_addr_space, MPC8544_PCI_REGS_OFFSET, 531dffb1dc2SBharat Bhushan sysbus_mmio_get_region(s, 0)); 532dffb1dc2SBharat Bhushan 533d461e3b9SAlexander Graf pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0"); 5341db09b84Saurel32 if (!pci_bus) 5351db09b84Saurel32 printf("couldn't create PCI controller!\n"); 5361db09b84Saurel32 537a1bc20dfSAlexander Graf sysbus_mmio_map(sysbus_from_qdev(dev), 1, MPC8544_PCI_IO); 5381db09b84Saurel32 5391db09b84Saurel32 if (pci_bus) { 5401db09b84Saurel32 /* Register network interfaces. */ 5411db09b84Saurel32 for (i = 0; i < nb_nics; i++) { 54207caea31SMarkus Armbruster pci_nic_init_nofail(&nd_table[i], "virtio", NULL); 5431db09b84Saurel32 } 5441db09b84Saurel32 } 5451db09b84Saurel32 5465c145dacSAlexander Graf /* Register spinning region */ 5475c145dacSAlexander Graf sysbus_create_simple("e500-spin", MPC8544_SPIN_BASE, NULL); 5485c145dacSAlexander Graf 5491db09b84Saurel32 /* Load kernel. */ 550e6eaabebSScott Wood if (params->kernel_filename) { 551e6eaabebSScott Wood kernel_size = load_uimage(params->kernel_filename, &entry, 552e6eaabebSScott Wood &loadaddr, NULL); 5531db09b84Saurel32 if (kernel_size < 0) { 554e6eaabebSScott Wood kernel_size = load_elf(params->kernel_filename, NULL, NULL, 555e6eaabebSScott Wood &elf_entry, &elf_lowaddr, NULL, 1, 556e6eaabebSScott Wood ELF_MACHINE, 0); 5571db09b84Saurel32 entry = elf_entry; 5581db09b84Saurel32 loadaddr = elf_lowaddr; 5591db09b84Saurel32 } 5601db09b84Saurel32 /* XXX try again as binary */ 5611db09b84Saurel32 if (kernel_size < 0) { 5621db09b84Saurel32 fprintf(stderr, "qemu: could not load kernel '%s'\n", 563e6eaabebSScott Wood params->kernel_filename); 5641db09b84Saurel32 exit(1); 5651db09b84Saurel32 } 5661db09b84Saurel32 } 5671db09b84Saurel32 5681db09b84Saurel32 /* Load initrd. */ 569e6eaabebSScott Wood if (params->initrd_filename) { 5707e7ec2d2SScott Wood initrd_base = (loadaddr + kernel_size + INITRD_LOAD_PAD) & 5717e7ec2d2SScott Wood ~INITRD_PAD_MASK; 572e6eaabebSScott Wood initrd_size = load_image_targphys(params->initrd_filename, initrd_base, 573d7585251Spbrook ram_size - initrd_base); 5741db09b84Saurel32 5751db09b84Saurel32 if (initrd_size < 0) { 5761db09b84Saurel32 fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", 577e6eaabebSScott Wood params->initrd_filename); 5781db09b84Saurel32 exit(1); 5791db09b84Saurel32 } 5801db09b84Saurel32 } 5811db09b84Saurel32 5821db09b84Saurel32 /* If we're loading a kernel directly, we must load the device tree too. */ 583e6eaabebSScott Wood if (params->kernel_filename) { 5845c145dacSAlexander Graf struct boot_info *boot_info; 585cba2026aSAlexander Graf int dt_size; 5865c145dacSAlexander Graf 587cba2026aSAlexander Graf dt_base = (loadaddr + kernel_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK; 588e6eaabebSScott Wood dt_size = ppce500_load_device_tree(env, params, dt_base, initrd_base, 589e6eaabebSScott Wood initrd_size); 590cba2026aSAlexander Graf if (dt_size < 0) { 5911db09b84Saurel32 fprintf(stderr, "couldn't load device tree\n"); 5921db09b84Saurel32 exit(1); 5931db09b84Saurel32 } 5941db09b84Saurel32 595e61c36d5SAlexander Graf boot_info = env->load_info; 5963b989d49SAlexander Graf boot_info->entry = entry; 5973b989d49SAlexander Graf boot_info->dt_base = dt_base; 598cba2026aSAlexander Graf boot_info->dt_size = dt_size; 5991db09b84Saurel32 } 6001db09b84Saurel32 6013b989d49SAlexander Graf if (kvm_enabled()) { 6021db09b84Saurel32 kvmppc_init(); 6033b989d49SAlexander Graf } 6041db09b84Saurel32 } 605*3eddc1beSBharat Bhushan 606*3eddc1beSBharat Bhushan static int e500_ccsr_initfn(SysBusDevice *dev) 607*3eddc1beSBharat Bhushan { 608*3eddc1beSBharat Bhushan PPCE500CCSRState *ccsr; 609*3eddc1beSBharat Bhushan 610*3eddc1beSBharat Bhushan ccsr = CCSR(dev); 611*3eddc1beSBharat Bhushan memory_region_init(&ccsr->ccsr_space, "e500-ccsr", 612*3eddc1beSBharat Bhushan MPC8544_CCSRBAR_SIZE); 613*3eddc1beSBharat Bhushan return 0; 614*3eddc1beSBharat Bhushan } 615*3eddc1beSBharat Bhushan 616*3eddc1beSBharat Bhushan static void e500_ccsr_class_init(ObjectClass *klass, void *data) 617*3eddc1beSBharat Bhushan { 618*3eddc1beSBharat Bhushan SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); 619*3eddc1beSBharat Bhushan k->init = e500_ccsr_initfn; 620*3eddc1beSBharat Bhushan } 621*3eddc1beSBharat Bhushan 622*3eddc1beSBharat Bhushan static const TypeInfo e500_ccsr_info = { 623*3eddc1beSBharat Bhushan .name = TYPE_CCSR, 624*3eddc1beSBharat Bhushan .parent = TYPE_SYS_BUS_DEVICE, 625*3eddc1beSBharat Bhushan .instance_size = sizeof(PPCE500CCSRState), 626*3eddc1beSBharat Bhushan .class_init = e500_ccsr_class_init, 627*3eddc1beSBharat Bhushan }; 628*3eddc1beSBharat Bhushan 629*3eddc1beSBharat Bhushan static void e500_register_types(void) 630*3eddc1beSBharat Bhushan { 631*3eddc1beSBharat Bhushan type_register_static(&e500_ccsr_info); 632*3eddc1beSBharat Bhushan } 633*3eddc1beSBharat Bhushan 634*3eddc1beSBharat Bhushan type_init(e500_register_types) 635