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 170d75590dSPeter Maydell #include "qemu/osdep.h" 18da34e65cSMarkus Armbruster #include "qapi/error.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" 328d085cf0SMark Cave-Ayland #include "hw/ppc/openpic_kvm.h" 330d09e41aSPaolo Bonzini #include "hw/ppc/ppc.h" 344a18e7c9SScott Wood #include "hw/loader.h" 35ca20cf32SBlue Swirl #include "elf.h" 364a18e7c9SScott Wood #include "hw/sysbus.h" 37022c62cbSPaolo Bonzini #include "exec/address-spaces.h" 381de7afc9SPaolo Bonzini #include "qemu/host-utils.h" 39922a01a0SMarkus Armbruster #include "qemu/option.h" 400d09e41aSPaolo Bonzini #include "hw/pci-host/ppce500.h" 41f7087343SAlexander Graf #include "qemu/error-report.h" 42f7087343SAlexander Graf #include "hw/platform-bus.h" 43fdfb7f2cSAlexander Graf #include "hw/net/fsl_etsec/etsec.h" 441db09b84Saurel32 45cefd3cdbSBharat Bhushan #define EPAPR_MAGIC (0x45504150) 461db09b84Saurel32 #define BINARY_DEVICE_TREE_FILE "mpc8544ds.dtb" 479dd5eba1SScott Wood #define DTC_LOAD_PAD 0x1800000 4875bb6589SLiu Yu #define DTC_PAD_MASK 0xFFFFF 49b8dec144SAlexander Graf #define DTB_MAX_SIZE (8 * 1024 * 1024) 5075bb6589SLiu Yu #define INITRD_LOAD_PAD 0x2000000 5175bb6589SLiu Yu #define INITRD_PAD_MASK 0xFFFFFF 521db09b84Saurel32 531db09b84Saurel32 #define RAM_SIZES_ALIGN (64UL << 20) 541db09b84Saurel32 55b3305981SScott Wood /* TODO: parameterize */ 56ed2bc496SAlexander Graf #define MPC8544_CCSRBAR_SIZE 0x00100000ULL 57dffb1dc2SBharat Bhushan #define MPC8544_MPIC_REGS_OFFSET 0x40000ULL 58a911b7a9SAlexander Graf #define MPC8544_MSI_REGS_OFFSET 0x41600ULL 59dffb1dc2SBharat Bhushan #define MPC8544_SERIAL0_REGS_OFFSET 0x4500ULL 60dffb1dc2SBharat Bhushan #define MPC8544_SERIAL1_REGS_OFFSET 0x4600ULL 61dffb1dc2SBharat Bhushan #define MPC8544_PCI_REGS_OFFSET 0x8000ULL 62ed2bc496SAlexander Graf #define MPC8544_PCI_REGS_SIZE 0x1000ULL 63dffb1dc2SBharat Bhushan #define MPC8544_UTIL_OFFSET 0xe0000ULL 64b88e77f4SAlexander Graf #define MPC8XXX_GPIO_OFFSET 0x000FF000ULL 6582e345f5SAmit Tomar #define MPC8XXX_GPIO_IRQ 47 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 { 109*2fb513d3SGreg Kurz char *ser; 110a053a7ceSAlexander Graf 111*2fb513d3SGreg Kurz ser = g_strdup_printf("%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) { 12390ee4e01SNikunj A Dadhania /* 12490ee4e01SNikunj A Dadhania * "linux,stdout-path" and "stdout" properties are deprecated by linux 12590ee4e01SNikunj A Dadhania * kernel. New platforms should only use the "stdout-path" property. Set 12690ee4e01SNikunj A Dadhania * the new property and continue using older property to remain 12790ee4e01SNikunj A Dadhania * compatible with the existing firmware. 12890ee4e01SNikunj A Dadhania */ 1295a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, "/chosen", "linux,stdout-path", ser); 13090ee4e01SNikunj A Dadhania qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", ser); 131a053a7ceSAlexander Graf } 132*2fb513d3SGreg Kurz g_free(ser); 133a053a7ceSAlexander Graf } 134a053a7ceSAlexander Graf 135b88e77f4SAlexander Graf static void create_dt_mpc8xxx_gpio(void *fdt, const char *soc, const char *mpic) 136b88e77f4SAlexander Graf { 137b88e77f4SAlexander Graf hwaddr mmio0 = MPC8XXX_GPIO_OFFSET; 138b88e77f4SAlexander Graf int irq0 = MPC8XXX_GPIO_IRQ; 139b88e77f4SAlexander Graf gchar *node = g_strdup_printf("%s/gpio@%"PRIx64, soc, mmio0); 140016f7758SAlexander Graf gchar *poweroff = g_strdup_printf("%s/power-off", soc); 141016f7758SAlexander Graf int gpio_ph; 142b88e77f4SAlexander Graf 143b88e77f4SAlexander Graf qemu_fdt_add_subnode(fdt, node); 144b88e77f4SAlexander Graf qemu_fdt_setprop_string(fdt, node, "compatible", "fsl,qoriq-gpio"); 145b88e77f4SAlexander Graf qemu_fdt_setprop_cells(fdt, node, "reg", mmio0, 0x1000); 146b88e77f4SAlexander Graf qemu_fdt_setprop_cells(fdt, node, "interrupts", irq0, 0x2); 147b88e77f4SAlexander Graf qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", mpic); 148b88e77f4SAlexander Graf qemu_fdt_setprop_cells(fdt, node, "#gpio-cells", 2); 149b88e77f4SAlexander Graf qemu_fdt_setprop(fdt, node, "gpio-controller", NULL, 0); 150016f7758SAlexander Graf gpio_ph = qemu_fdt_alloc_phandle(fdt); 151016f7758SAlexander Graf qemu_fdt_setprop_cell(fdt, node, "phandle", gpio_ph); 152016f7758SAlexander Graf qemu_fdt_setprop_cell(fdt, node, "linux,phandle", gpio_ph); 153016f7758SAlexander Graf 154016f7758SAlexander Graf /* Power Off Pin */ 155016f7758SAlexander Graf qemu_fdt_add_subnode(fdt, poweroff); 156016f7758SAlexander Graf qemu_fdt_setprop_string(fdt, poweroff, "compatible", "gpio-poweroff"); 157016f7758SAlexander Graf qemu_fdt_setprop_cells(fdt, poweroff, "gpios", gpio_ph, 0, 0); 158b88e77f4SAlexander Graf 159b88e77f4SAlexander Graf g_free(node); 160016f7758SAlexander Graf g_free(poweroff); 161b88e77f4SAlexander Graf } 162b88e77f4SAlexander Graf 163f7087343SAlexander Graf typedef struct PlatformDevtreeData { 164f7087343SAlexander Graf void *fdt; 165f7087343SAlexander Graf const char *mpic; 166f7087343SAlexander Graf int irq_start; 167f7087343SAlexander Graf const char *node; 168f7087343SAlexander Graf PlatformBusDevice *pbus; 169f7087343SAlexander Graf } PlatformDevtreeData; 170f7087343SAlexander Graf 171fdfb7f2cSAlexander Graf static int create_devtree_etsec(SysBusDevice *sbdev, PlatformDevtreeData *data) 172fdfb7f2cSAlexander Graf { 173fdfb7f2cSAlexander Graf eTSEC *etsec = ETSEC_COMMON(sbdev); 174fdfb7f2cSAlexander Graf PlatformBusDevice *pbus = data->pbus; 175fdfb7f2cSAlexander Graf hwaddr mmio0 = platform_bus_get_mmio_addr(pbus, sbdev, 0); 176fdfb7f2cSAlexander Graf int irq0 = platform_bus_get_irqn(pbus, sbdev, 0); 177fdfb7f2cSAlexander Graf int irq1 = platform_bus_get_irqn(pbus, sbdev, 1); 178fdfb7f2cSAlexander Graf int irq2 = platform_bus_get_irqn(pbus, sbdev, 2); 179fdfb7f2cSAlexander Graf gchar *node = g_strdup_printf("/platform/ethernet@%"PRIx64, mmio0); 180fdfb7f2cSAlexander Graf gchar *group = g_strdup_printf("%s/queue-group", node); 181fdfb7f2cSAlexander Graf void *fdt = data->fdt; 182fdfb7f2cSAlexander Graf 183fdfb7f2cSAlexander Graf assert((int64_t)mmio0 >= 0); 184fdfb7f2cSAlexander Graf assert(irq0 >= 0); 185fdfb7f2cSAlexander Graf assert(irq1 >= 0); 186fdfb7f2cSAlexander Graf assert(irq2 >= 0); 187fdfb7f2cSAlexander Graf 188fdfb7f2cSAlexander Graf qemu_fdt_add_subnode(fdt, node); 189fdfb7f2cSAlexander Graf qemu_fdt_setprop_string(fdt, node, "device_type", "network"); 190fdfb7f2cSAlexander Graf qemu_fdt_setprop_string(fdt, node, "compatible", "fsl,etsec2"); 191fdfb7f2cSAlexander Graf qemu_fdt_setprop_string(fdt, node, "model", "eTSEC"); 192fdfb7f2cSAlexander Graf qemu_fdt_setprop(fdt, node, "local-mac-address", etsec->conf.macaddr.a, 6); 193fdfb7f2cSAlexander Graf qemu_fdt_setprop_cells(fdt, node, "fixed-link", 0, 1, 1000, 0, 0); 194fdfb7f2cSAlexander Graf 195fdfb7f2cSAlexander Graf qemu_fdt_add_subnode(fdt, group); 196fdfb7f2cSAlexander Graf qemu_fdt_setprop_cells(fdt, group, "reg", mmio0, 0x1000); 197fdfb7f2cSAlexander Graf qemu_fdt_setprop_cells(fdt, group, "interrupts", 198fdfb7f2cSAlexander Graf data->irq_start + irq0, 0x2, 199fdfb7f2cSAlexander Graf data->irq_start + irq1, 0x2, 200fdfb7f2cSAlexander Graf data->irq_start + irq2, 0x2); 201fdfb7f2cSAlexander Graf 202fdfb7f2cSAlexander Graf g_free(node); 203fdfb7f2cSAlexander Graf g_free(group); 204fdfb7f2cSAlexander Graf 205fdfb7f2cSAlexander Graf return 0; 206fdfb7f2cSAlexander Graf } 207fdfb7f2cSAlexander Graf 2084f01a637SDavid Gibson static void sysbus_device_create_devtree(SysBusDevice *sbdev, void *opaque) 209f7087343SAlexander Graf { 210f7087343SAlexander Graf PlatformDevtreeData *data = opaque; 211f7087343SAlexander Graf bool matched = false; 212f7087343SAlexander Graf 213fdfb7f2cSAlexander Graf if (object_dynamic_cast(OBJECT(sbdev), TYPE_ETSEC_COMMON)) { 214fdfb7f2cSAlexander Graf create_devtree_etsec(sbdev, data); 215fdfb7f2cSAlexander Graf matched = true; 216fdfb7f2cSAlexander Graf } 217fdfb7f2cSAlexander Graf 218f7087343SAlexander Graf if (!matched) { 219f7087343SAlexander Graf error_report("Device %s is not supported by this machine yet.", 220f7087343SAlexander Graf qdev_fw_name(DEVICE(sbdev))); 221f7087343SAlexander Graf exit(1); 222f7087343SAlexander Graf } 223f7087343SAlexander Graf } 224f7087343SAlexander Graf 22503f04809SIgor Mammedov static void platform_bus_create_devtree(const PPCE500MachineClass *pmc, 22603f04809SIgor Mammedov void *fdt, const char *mpic) 227f7087343SAlexander Graf { 22803f04809SIgor Mammedov gchar *node = g_strdup_printf("/platform@%"PRIx64, pmc->platform_bus_base); 229f7087343SAlexander Graf const char platcomp[] = "qemu,platform\0simple-bus"; 23003f04809SIgor Mammedov uint64_t addr = pmc->platform_bus_base; 23103f04809SIgor Mammedov uint64_t size = pmc->platform_bus_size; 23203f04809SIgor Mammedov int irq_start = pmc->platform_bus_first_irq; 233f7087343SAlexander Graf PlatformBusDevice *pbus; 234f7087343SAlexander Graf DeviceState *dev; 235f7087343SAlexander Graf 236f7087343SAlexander Graf /* Create a /platform node that we can put all devices into */ 237f7087343SAlexander Graf 238f7087343SAlexander Graf qemu_fdt_add_subnode(fdt, node); 239f7087343SAlexander Graf qemu_fdt_setprop(fdt, node, "compatible", platcomp, sizeof(platcomp)); 240f7087343SAlexander Graf 241f7087343SAlexander Graf /* Our platform bus region is less than 32bit big, so 1 cell is enough for 242f7087343SAlexander Graf address and size */ 243f7087343SAlexander Graf qemu_fdt_setprop_cells(fdt, node, "#size-cells", 1); 244f7087343SAlexander Graf qemu_fdt_setprop_cells(fdt, node, "#address-cells", 1); 245f7087343SAlexander Graf qemu_fdt_setprop_cells(fdt, node, "ranges", 0, addr >> 32, addr, size); 246f7087343SAlexander Graf 247f7087343SAlexander Graf qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", mpic); 248f7087343SAlexander Graf 249f7087343SAlexander Graf dev = qdev_find_recursive(sysbus_get_default(), TYPE_PLATFORM_BUS_DEVICE); 250f7087343SAlexander Graf pbus = PLATFORM_BUS_DEVICE(dev); 251f7087343SAlexander Graf 252f7087343SAlexander Graf /* We can only create dt nodes for dynamic devices when they're ready */ 253f7087343SAlexander Graf if (pbus->done_gathering) { 254f7087343SAlexander Graf PlatformDevtreeData data = { 255f7087343SAlexander Graf .fdt = fdt, 256f7087343SAlexander Graf .mpic = mpic, 257f7087343SAlexander Graf .irq_start = irq_start, 258f7087343SAlexander Graf .node = node, 259f7087343SAlexander Graf .pbus = pbus, 260f7087343SAlexander Graf }; 261f7087343SAlexander Graf 262f7087343SAlexander Graf /* Loop through all dynamic sysbus devices and create nodes for them */ 263f7087343SAlexander Graf foreach_dynamic_sysbus_device(sysbus_device_create_devtree, &data); 264f7087343SAlexander Graf } 265f7087343SAlexander Graf 266f7087343SAlexander Graf g_free(node); 267f7087343SAlexander Graf } 268f7087343SAlexander Graf 26903f04809SIgor Mammedov static int ppce500_load_device_tree(PPCE500MachineState *pms, 270a8170e5eSAvi Kivity hwaddr addr, 271a8170e5eSAvi Kivity hwaddr initrd_base, 27228290f37SAlexander Graf hwaddr initrd_size, 273903585deSAlexander Graf hwaddr kernel_base, 274903585deSAlexander Graf hwaddr kernel_size, 27528290f37SAlexander Graf bool dry_run) 2761db09b84Saurel32 { 27703f04809SIgor Mammedov MachineState *machine = MACHINE(pms); 27803f04809SIgor Mammedov const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(pms); 27928290f37SAlexander Graf CPUPPCState *env = first_cpu->env_ptr; 280dbf916d8SAurelien Jarno int ret = -1; 2813ef96221SMarcel Apfelbaum uint64_t mem_reg_property[] = { 0, cpu_to_be64(machine->ram_size) }; 2827ec632b4Spbrook int fdt_size; 283dbf916d8SAurelien Jarno void *fdt; 2845de6b46dSAlexander Graf uint8_t hypercall[16]; 285911d6e7aSAlexander Graf uint32_t clock_freq = 400000000; 286911d6e7aSAlexander Graf uint32_t tb_freq = 400000000; 287621d05e3SAlexander Graf int i; 288ebb9518aSAlexander Graf char compatible_sb[] = "fsl,mpc8544-immr\0simple-bus"; 289*2fb513d3SGreg Kurz char *soc; 290*2fb513d3SGreg Kurz char *mpic; 29119ac9deaSAlexander Graf uint32_t mpic_ph; 292a911b7a9SAlexander Graf uint32_t msi_ph; 293*2fb513d3SGreg Kurz char *gutil; 294*2fb513d3SGreg Kurz char *pci; 295*2fb513d3SGreg Kurz char *msi; 296347dd79dSAlexander Graf uint32_t *pci_map = NULL; 297347dd79dSAlexander Graf int len; 2983627757eSAlexander Graf uint32_t pci_ranges[14] = 2993627757eSAlexander Graf { 30003f04809SIgor Mammedov 0x2000000, 0x0, pmc->pci_mmio_bus_base, 30103f04809SIgor Mammedov pmc->pci_mmio_base >> 32, pmc->pci_mmio_base, 3023627757eSAlexander Graf 0x0, 0x20000000, 3033627757eSAlexander Graf 3043627757eSAlexander Graf 0x1000000, 0x0, 0x0, 30503f04809SIgor Mammedov pmc->pci_pio_base >> 32, pmc->pci_pio_base, 3063627757eSAlexander Graf 0x0, 0x10000, 3073627757eSAlexander Graf }; 3082ff3de68SMarkus Armbruster QemuOpts *machine_opts = qemu_get_machine_opts(); 3092ff3de68SMarkus Armbruster const char *dtb_file = qemu_opt_get(machine_opts, "dtb"); 3102ff3de68SMarkus Armbruster const char *toplevel_compat = qemu_opt_get(machine_opts, "dt_compatible"); 311d1b93565SAlexander Graf 312d1b93565SAlexander Graf if (dtb_file) { 313d1b93565SAlexander Graf char *filename; 314d1b93565SAlexander Graf filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_file); 315d1b93565SAlexander Graf if (!filename) { 316d1b93565SAlexander Graf goto out; 317d1b93565SAlexander Graf } 318d1b93565SAlexander Graf 319d1b93565SAlexander Graf fdt = load_device_tree(filename, &fdt_size); 3202343dd11SMichael Tokarev g_free(filename); 321d1b93565SAlexander Graf if (!fdt) { 322d1b93565SAlexander Graf goto out; 323d1b93565SAlexander Graf } 324d1b93565SAlexander Graf goto done; 325d1b93565SAlexander Graf } 3261db09b84Saurel32 3272636fcb6SAlexander Graf fdt = create_device_tree(&fdt_size); 3285cea8590SPaul Brook if (fdt == NULL) { 3295cea8590SPaul Brook goto out; 3305cea8590SPaul Brook } 3311db09b84Saurel32 3321db09b84Saurel32 /* Manipulate device tree in memory. */ 3335a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 2); 3345a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 2); 33551b852b7SAlexander Graf 3365a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, "/memory"); 3375a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, "/memory", "device_type", "memory"); 3385a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, "/memory", "reg", mem_reg_property, 3391db09b84Saurel32 sizeof(mem_reg_property)); 3401db09b84Saurel32 3415a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, "/chosen"); 3423b989d49SAlexander Graf if (initrd_size) { 3435a4348d1SPeter Crosthwaite ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start", 3441db09b84Saurel32 initrd_base); 3453b989d49SAlexander Graf if (ret < 0) { 3461db09b84Saurel32 fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n"); 3473b989d49SAlexander Graf } 3481db09b84Saurel32 3495a4348d1SPeter Crosthwaite ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end", 3501db09b84Saurel32 (initrd_base + initrd_size)); 3513b989d49SAlexander Graf if (ret < 0) { 3521db09b84Saurel32 fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n"); 3533b989d49SAlexander Graf } 354903585deSAlexander Graf 355903585deSAlexander Graf } 356903585deSAlexander Graf 357903585deSAlexander Graf if (kernel_base != -1ULL) { 358903585deSAlexander Graf qemu_fdt_setprop_cells(fdt, "/chosen", "qemu,boot-kernel", 359903585deSAlexander Graf kernel_base >> 32, kernel_base, 360903585deSAlexander Graf kernel_size >> 32, kernel_size); 3613b989d49SAlexander Graf } 3621db09b84Saurel32 3635a4348d1SPeter Crosthwaite ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", 3643ef96221SMarcel Apfelbaum machine->kernel_cmdline); 3651db09b84Saurel32 if (ret < 0) 3661db09b84Saurel32 fprintf(stderr, "couldn't set /chosen/bootargs\n"); 3671db09b84Saurel32 3681db09b84Saurel32 if (kvm_enabled()) { 369911d6e7aSAlexander Graf /* Read out host's frequencies */ 370911d6e7aSAlexander Graf clock_freq = kvmppc_get_clockfreq(); 371911d6e7aSAlexander Graf tb_freq = kvmppc_get_tbfreq(); 3725de6b46dSAlexander Graf 3735de6b46dSAlexander Graf /* indicate KVM hypercall interface */ 3745a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, "/hypervisor"); 3755a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, "/hypervisor", "compatible", 3765de6b46dSAlexander Graf "linux,kvm"); 3775de6b46dSAlexander Graf kvmppc_get_hypercall(env, hypercall, sizeof(hypercall)); 3785a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, "/hypervisor", "hcall-instructions", 3795de6b46dSAlexander Graf hypercall, sizeof(hypercall)); 3801a61a9aeSStuart Yoder /* if KVM supports the idle hcall, set property indicating this */ 3811a61a9aeSStuart Yoder if (kvmppc_get_hasidle(env)) { 3825a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, "/hypervisor", "has-idle", NULL, 0); 3831a61a9aeSStuart Yoder } 3841db09b84Saurel32 } 3851db09b84Saurel32 386625e665bSAlexander Graf /* Create CPU nodes */ 3875a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, "/cpus"); 3885a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 1); 3895a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0); 390625e665bSAlexander Graf 3911e3debf0SAlexander Graf /* We need to generate the cpu nodes in reverse order, so Linux can pick 3921e3debf0SAlexander Graf the first node as boot node and be happy */ 3931e3debf0SAlexander Graf for (i = smp_cpus - 1; i >= 0; i--) { 394440c8152SAndreas Färber CPUState *cpu; 395*2fb513d3SGreg Kurz char *cpu_name; 39603f04809SIgor Mammedov uint64_t cpu_release_addr = pmc->spin_base + (i * 0x20); 39710f25a46SAlexander Graf 398440c8152SAndreas Färber cpu = qemu_get_cpu(i); 39955e5c285SAndreas Färber if (cpu == NULL) { 4001e3debf0SAlexander Graf continue; 4011e3debf0SAlexander Graf } 402440c8152SAndreas Färber env = cpu->env_ptr; 4031e3debf0SAlexander Graf 404*2fb513d3SGreg Kurz cpu_name = g_strdup_printf("/cpus/PowerPC,8544@%x", i); 4055a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, cpu_name); 4065a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq); 4075a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq); 4085a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, cpu_name, "device_type", "cpu"); 4096d536570SSam Bobroff qemu_fdt_setprop_cell(fdt, cpu_name, "reg", i); 4105a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-line-size", 4111e3debf0SAlexander Graf env->dcache_line_size); 4125a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-line-size", 4131e3debf0SAlexander Graf env->icache_line_size); 4145a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-size", 0x8000); 4155a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-size", 0x8000); 4165a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "bus-frequency", 0); 41755e5c285SAndreas Färber if (cpu->cpu_index) { 4185a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, cpu_name, "status", "disabled"); 4195a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, cpu_name, "enable-method", 4205a4348d1SPeter Crosthwaite "spin-table"); 4215a4348d1SPeter Crosthwaite qemu_fdt_setprop_u64(fdt, cpu_name, "cpu-release-addr", 4221d2e5c52SAlexander Graf cpu_release_addr); 4231e3debf0SAlexander Graf } else { 4245a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, cpu_name, "status", "okay"); 4251e3debf0SAlexander Graf } 426*2fb513d3SGreg Kurz g_free(cpu_name); 4271db09b84Saurel32 } 4281db09b84Saurel32 4295a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, "/aliases"); 4305da96624SAlexander Graf /* XXX These should go into their respective devices' code */ 431*2fb513d3SGreg Kurz soc = g_strdup_printf("/soc@%"PRIx64, pmc->ccsrbar_base); 4325a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, soc); 4335a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, soc, "device_type", "soc"); 4345a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, soc, "compatible", compatible_sb, 435ebb9518aSAlexander Graf sizeof(compatible_sb)); 4365a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, soc, "#address-cells", 1); 4375a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, soc, "#size-cells", 1); 4385a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, soc, "ranges", 0x0, 43903f04809SIgor Mammedov pmc->ccsrbar_base >> 32, pmc->ccsrbar_base, 4405da96624SAlexander Graf MPC8544_CCSRBAR_SIZE); 4415da96624SAlexander Graf /* XXX should contain a reasonable value */ 4425a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, soc, "bus-frequency", 0); 4435da96624SAlexander Graf 444*2fb513d3SGreg Kurz mpic = g_strdup_printf("%s/pic@%llx", soc, MPC8544_MPIC_REGS_OFFSET); 4455a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, mpic); 4465a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, mpic, "device_type", "open-pic"); 4475a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, mpic, "compatible", "fsl,mpic"); 4485a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_OFFSET, 449dffb1dc2SBharat Bhushan 0x40000); 4505a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, mpic, "#address-cells", 0); 4515a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, mpic, "#interrupt-cells", 2); 4525a4348d1SPeter Crosthwaite mpic_ph = qemu_fdt_alloc_phandle(fdt); 4535a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, mpic, "phandle", mpic_ph); 4545a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, mpic, "linux,phandle", mpic_ph); 4555a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, mpic, "interrupt-controller", NULL, 0); 45619ac9deaSAlexander Graf 4570cfc6e8dSAlexander Graf /* 4580cfc6e8dSAlexander Graf * We have to generate ser1 first, because Linux takes the first 4590cfc6e8dSAlexander Graf * device it finds in the dt as serial output device. And we generate 4600cfc6e8dSAlexander Graf * devices in reverse order to the dt. 4610cfc6e8dSAlexander Graf */ 4629bca0edbSPeter Maydell if (serial_hd(1)) { 463dffb1dc2SBharat Bhushan dt_serial_create(fdt, MPC8544_SERIAL1_REGS_OFFSET, 464a053a7ceSAlexander Graf soc, mpic, "serial1", 1, false); 46579c0ff2cSAlexander Graf } 46679c0ff2cSAlexander Graf 4679bca0edbSPeter Maydell if (serial_hd(0)) { 468dffb1dc2SBharat Bhushan dt_serial_create(fdt, MPC8544_SERIAL0_REGS_OFFSET, 469a053a7ceSAlexander Graf soc, mpic, "serial0", 0, true); 47079c0ff2cSAlexander Graf } 4710cfc6e8dSAlexander Graf 472*2fb513d3SGreg Kurz gutil = g_strdup_printf("%s/global-utilities@%llx", soc, 473dffb1dc2SBharat Bhushan MPC8544_UTIL_OFFSET); 4745a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, gutil); 4755a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, gutil, "compatible", "fsl,mpc8544-guts"); 4765a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, gutil, "reg", MPC8544_UTIL_OFFSET, 0x1000); 4775a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, gutil, "fsl,has-rstcr", NULL, 0); 478*2fb513d3SGreg Kurz g_free(gutil); 479f5038483SAlexander Graf 480*2fb513d3SGreg Kurz msi = g_strdup_printf("/%s/msi@%llx", soc, MPC8544_MSI_REGS_OFFSET); 4815a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, msi); 4825a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, msi, "compatible", "fsl,mpic-msi"); 4835a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, msi, "reg", MPC8544_MSI_REGS_OFFSET, 0x200); 4845a4348d1SPeter Crosthwaite msi_ph = qemu_fdt_alloc_phandle(fdt); 4855a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, msi, "msi-available-ranges", 0x0, 0x100); 4865a4348d1SPeter Crosthwaite qemu_fdt_setprop_phandle(fdt, msi, "interrupt-parent", mpic); 4875a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, msi, "interrupts", 488a911b7a9SAlexander Graf 0xe0, 0x0, 489a911b7a9SAlexander Graf 0xe1, 0x0, 490a911b7a9SAlexander Graf 0xe2, 0x0, 491a911b7a9SAlexander Graf 0xe3, 0x0, 492a911b7a9SAlexander Graf 0xe4, 0x0, 493a911b7a9SAlexander Graf 0xe5, 0x0, 494a911b7a9SAlexander Graf 0xe6, 0x0, 495a911b7a9SAlexander Graf 0xe7, 0x0); 4965a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, msi, "phandle", msi_ph); 4975a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, msi, "linux,phandle", msi_ph); 498*2fb513d3SGreg Kurz g_free(msi); 499a911b7a9SAlexander Graf 500*2fb513d3SGreg Kurz pci = g_strdup_printf("/pci@%llx", 50103f04809SIgor Mammedov pmc->ccsrbar_base + MPC8544_PCI_REGS_OFFSET); 5025a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, pci); 5035a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, pci, "cell-index", 0); 5045a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, pci, "compatible", "fsl,mpc8540-pci"); 5055a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, pci, "device_type", "pci"); 5065a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, pci, "interrupt-map-mask", 0xf800, 0x0, 5070dbc0798SAlexander Graf 0x0, 0x7); 5085a4348d1SPeter Crosthwaite pci_map = pci_map_create(fdt, qemu_fdt_get_phandle(fdt, mpic), 50903f04809SIgor Mammedov pmc->pci_first_slot, pmc->pci_nr_slots, 510492ec48dSAlexander Graf &len); 5115a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, pci, "interrupt-map", pci_map, len); 5125a4348d1SPeter Crosthwaite qemu_fdt_setprop_phandle(fdt, pci, "interrupt-parent", mpic); 5135a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, pci, "interrupts", 24, 2); 5145a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, pci, "bus-range", 0, 255); 5153627757eSAlexander Graf for (i = 0; i < 14; i++) { 5160dbc0798SAlexander Graf pci_ranges[i] = cpu_to_be32(pci_ranges[i]); 5170dbc0798SAlexander Graf } 5185a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, pci, "fsl,msi", msi_ph); 5195a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, pci, "ranges", pci_ranges, sizeof(pci_ranges)); 5202eaaac1fSAlexander Graf qemu_fdt_setprop_cells(fdt, pci, "reg", 52103f04809SIgor Mammedov (pmc->ccsrbar_base + MPC8544_PCI_REGS_OFFSET) >> 32, 52203f04809SIgor Mammedov (pmc->ccsrbar_base + MPC8544_PCI_REGS_OFFSET), 5232eaaac1fSAlexander Graf 0, 0x1000); 5245a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, pci, "clock-frequency", 66666666); 5255a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, pci, "#interrupt-cells", 1); 5265a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, pci, "#size-cells", 2); 5275a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, pci, "#address-cells", 3); 5285a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, "/aliases", "pci0", pci); 529*2fb513d3SGreg Kurz g_free(pci); 5300dbc0798SAlexander Graf 53103f04809SIgor Mammedov if (pmc->has_mpc8xxx_gpio) { 532b88e77f4SAlexander Graf create_dt_mpc8xxx_gpio(fdt, soc, mpic); 533b88e77f4SAlexander Graf } 534*2fb513d3SGreg Kurz g_free(soc); 535b88e77f4SAlexander Graf 53603f04809SIgor Mammedov if (pmc->has_platform_bus) { 53703f04809SIgor Mammedov platform_bus_create_devtree(pmc, fdt, mpic); 538f7087343SAlexander Graf } 539*2fb513d3SGreg Kurz g_free(mpic); 540f7087343SAlexander Graf 54103f04809SIgor Mammedov pmc->fixup_devtree(fdt); 542e6eaabebSScott Wood 543e6eaabebSScott Wood if (toplevel_compat) { 5445a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, "/", "compatible", toplevel_compat, 545e6eaabebSScott Wood strlen(toplevel_compat) + 1); 546e6eaabebSScott Wood } 547e6eaabebSScott Wood 548d1b93565SAlexander Graf done: 54928290f37SAlexander Graf if (!dry_run) { 5505a4348d1SPeter Crosthwaite qemu_fdt_dumpdtb(fdt, fdt_size); 55128290f37SAlexander Graf cpu_physical_memory_write(addr, fdt, fdt_size); 552cba2026aSAlexander Graf } 553cba2026aSAlexander Graf ret = fdt_size; 5547ec632b4Spbrook 5551db09b84Saurel32 out: 556347dd79dSAlexander Graf g_free(pci_map); 5571db09b84Saurel32 55804088adbSLiu Yu return ret; 5591db09b84Saurel32 } 5601db09b84Saurel32 56128290f37SAlexander Graf typedef struct DeviceTreeParams { 56203f04809SIgor Mammedov PPCE500MachineState *machine; 56328290f37SAlexander Graf hwaddr addr; 56428290f37SAlexander Graf hwaddr initrd_base; 56528290f37SAlexander Graf hwaddr initrd_size; 566903585deSAlexander Graf hwaddr kernel_base; 567903585deSAlexander Graf hwaddr kernel_size; 568f7087343SAlexander Graf Notifier notifier; 56928290f37SAlexander Graf } DeviceTreeParams; 57028290f37SAlexander Graf 57128290f37SAlexander Graf static void ppce500_reset_device_tree(void *opaque) 57228290f37SAlexander Graf { 57328290f37SAlexander Graf DeviceTreeParams *p = opaque; 57403f04809SIgor Mammedov ppce500_load_device_tree(p->machine, p->addr, p->initrd_base, 575903585deSAlexander Graf p->initrd_size, p->kernel_base, p->kernel_size, 576903585deSAlexander Graf false); 57728290f37SAlexander Graf } 57828290f37SAlexander Graf 579f7087343SAlexander Graf static void ppce500_init_notify(Notifier *notifier, void *data) 580f7087343SAlexander Graf { 581f7087343SAlexander Graf DeviceTreeParams *p = container_of(notifier, DeviceTreeParams, notifier); 582f7087343SAlexander Graf ppce500_reset_device_tree(p); 583f7087343SAlexander Graf } 584f7087343SAlexander Graf 58503f04809SIgor Mammedov static int ppce500_prep_device_tree(PPCE500MachineState *machine, 58628290f37SAlexander Graf hwaddr addr, 58728290f37SAlexander Graf hwaddr initrd_base, 588903585deSAlexander Graf hwaddr initrd_size, 589903585deSAlexander Graf hwaddr kernel_base, 590903585deSAlexander Graf hwaddr kernel_size) 59128290f37SAlexander Graf { 59228290f37SAlexander Graf DeviceTreeParams *p = g_new(DeviceTreeParams, 1); 5933ef96221SMarcel Apfelbaum p->machine = machine; 59428290f37SAlexander Graf p->addr = addr; 59528290f37SAlexander Graf p->initrd_base = initrd_base; 59628290f37SAlexander Graf p->initrd_size = initrd_size; 597903585deSAlexander Graf p->kernel_base = kernel_base; 598903585deSAlexander Graf p->kernel_size = kernel_size; 59928290f37SAlexander Graf 60028290f37SAlexander Graf qemu_register_reset(ppce500_reset_device_tree, p); 601f7087343SAlexander Graf p->notifier.notify = ppce500_init_notify; 602f7087343SAlexander Graf qemu_add_machine_init_done_notifier(&p->notifier); 60328290f37SAlexander Graf 60428290f37SAlexander Graf /* Issue the device tree loader once, so that we get the size of the blob */ 60503f04809SIgor Mammedov return ppce500_load_device_tree(machine, addr, initrd_base, initrd_size, 60603f04809SIgor Mammedov kernel_base, kernel_size, true); 60728290f37SAlexander Graf } 60828290f37SAlexander Graf 609cba2026aSAlexander Graf /* Create -kernel TLB entries for BookE. */ 610a36848ffSAaron Larson hwaddr booke206_page_size_to_tlb(uint64_t size) 611d1e256feSAlexander Graf { 612cba2026aSAlexander Graf return 63 - clz64(size >> 10); 613d1e256feSAlexander Graf } 614d1e256feSAlexander Graf 615cefd3cdbSBharat Bhushan static int booke206_initial_map_tsize(CPUPPCState *env) 6163b989d49SAlexander Graf { 617cba2026aSAlexander Graf struct boot_info *bi = env->load_info; 618cefd3cdbSBharat Bhushan hwaddr dt_end; 619cba2026aSAlexander Graf int ps; 6203b989d49SAlexander Graf 621cba2026aSAlexander Graf /* Our initial TLB entry needs to cover everything from 0 to 622cba2026aSAlexander Graf the device tree top */ 623cba2026aSAlexander Graf dt_end = bi->dt_base + bi->dt_size; 624cba2026aSAlexander Graf ps = booke206_page_size_to_tlb(dt_end) + 1; 625fb37c302SAlexander Graf if (ps & 1) { 626fb37c302SAlexander Graf /* e500v2 can only do even TLB size bits */ 627fb37c302SAlexander Graf ps++; 628fb37c302SAlexander Graf } 629cefd3cdbSBharat Bhushan return ps; 630cefd3cdbSBharat Bhushan } 631cefd3cdbSBharat Bhushan 632cefd3cdbSBharat Bhushan static uint64_t mmubooke_initial_mapsize(CPUPPCState *env) 633cefd3cdbSBharat Bhushan { 634cefd3cdbSBharat Bhushan int tsize; 635cefd3cdbSBharat Bhushan 636cefd3cdbSBharat Bhushan tsize = booke206_initial_map_tsize(env); 637cefd3cdbSBharat Bhushan return (1ULL << 10 << tsize); 638cefd3cdbSBharat Bhushan } 639cefd3cdbSBharat Bhushan 640cefd3cdbSBharat Bhushan static void mmubooke_create_initial_mapping(CPUPPCState *env) 641cefd3cdbSBharat Bhushan { 642cefd3cdbSBharat Bhushan ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0); 643cefd3cdbSBharat Bhushan hwaddr size; 644cefd3cdbSBharat Bhushan int ps; 645cefd3cdbSBharat Bhushan 646cefd3cdbSBharat Bhushan ps = booke206_initial_map_tsize(env); 647cba2026aSAlexander Graf size = (ps << MAS1_TSIZE_SHIFT); 648d1e256feSAlexander Graf tlb->mas1 = MAS1_VALID | size; 649cba2026aSAlexander Graf tlb->mas2 = 0; 650cba2026aSAlexander Graf tlb->mas7_3 = 0; 651d1e256feSAlexander Graf tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX; 65293dd5e85SScott Wood 65393dd5e85SScott Wood env->tlb_dirty = true; 6543b989d49SAlexander Graf } 6553b989d49SAlexander Graf 656b3305981SScott Wood static void ppce500_cpu_reset_sec(void *opaque) 6575c145dacSAlexander Graf { 65838f92da6SAndreas Färber PowerPCCPU *cpu = opaque; 659259186a7SAndreas Färber CPUState *cs = CPU(cpu); 6605c145dacSAlexander Graf 661259186a7SAndreas Färber cpu_reset(cs); 6625c145dacSAlexander Graf 6635c145dacSAlexander Graf /* Secondary CPU starts in halted state for now. Needs to change when 6645c145dacSAlexander Graf implementing non-kernel boot. */ 665259186a7SAndreas Färber cs->halted = 1; 66627103424SAndreas Färber cs->exception_index = EXCP_HLT; 6673b989d49SAlexander Graf } 6683b989d49SAlexander Graf 669b3305981SScott Wood static void ppce500_cpu_reset(void *opaque) 6703b989d49SAlexander Graf { 67138f92da6SAndreas Färber PowerPCCPU *cpu = opaque; 672259186a7SAndreas Färber CPUState *cs = CPU(cpu); 67338f92da6SAndreas Färber CPUPPCState *env = &cpu->env; 6743b989d49SAlexander Graf struct boot_info *bi = env->load_info; 6753b989d49SAlexander Graf 676259186a7SAndreas Färber cpu_reset(cs); 6773b989d49SAlexander Graf 6783b989d49SAlexander Graf /* Set initial guest state. */ 679259186a7SAndreas Färber cs->halted = 0; 6803b989d49SAlexander Graf env->gpr[1] = (16<<20) - 8; 6813b989d49SAlexander Graf env->gpr[3] = bi->dt_base; 682cefd3cdbSBharat Bhushan env->gpr[4] = 0; 683cefd3cdbSBharat Bhushan env->gpr[5] = 0; 684cefd3cdbSBharat Bhushan env->gpr[6] = EPAPR_MAGIC; 685cefd3cdbSBharat Bhushan env->gpr[7] = mmubooke_initial_mapsize(env); 686cefd3cdbSBharat Bhushan env->gpr[8] = 0; 687cefd3cdbSBharat Bhushan env->gpr[9] = 0; 6883b989d49SAlexander Graf env->nip = bi->entry; 689cba2026aSAlexander Graf mmubooke_create_initial_mapping(env); 6903b989d49SAlexander Graf } 6913b989d49SAlexander Graf 69203f04809SIgor Mammedov static DeviceState *ppce500_init_mpic_qemu(PPCE500MachineState *pms, 69382fc73b6SScott Wood qemu_irq **irqs) 69482fc73b6SScott Wood { 69582fc73b6SScott Wood DeviceState *dev; 69682fc73b6SScott Wood SysBusDevice *s; 69782fc73b6SScott Wood int i, j, k; 69803f04809SIgor Mammedov MachineState *machine = MACHINE(pms); 69903f04809SIgor Mammedov const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(pms); 70082fc73b6SScott Wood 701e1766344SAndreas Färber dev = qdev_create(NULL, TYPE_OPENPIC); 70203f04809SIgor Mammedov object_property_add_child(OBJECT(machine), "pic", OBJECT(dev), 703e75ce32aSMichael Davidsaver &error_fatal); 70403f04809SIgor Mammedov qdev_prop_set_uint32(dev, "model", pmc->mpic_version); 705d85937e6SScott Wood qdev_prop_set_uint32(dev, "nb_cpus", smp_cpus); 706d85937e6SScott Wood 70782fc73b6SScott Wood qdev_init_nofail(dev); 70882fc73b6SScott Wood s = SYS_BUS_DEVICE(dev); 70982fc73b6SScott Wood 71082fc73b6SScott Wood k = 0; 71182fc73b6SScott Wood for (i = 0; i < smp_cpus; i++) { 71282fc73b6SScott Wood for (j = 0; j < OPENPIC_OUTPUT_NB; j++) { 71382fc73b6SScott Wood sysbus_connect_irq(s, k++, irqs[i][j]); 71482fc73b6SScott Wood } 71582fc73b6SScott Wood } 71682fc73b6SScott Wood 717d85937e6SScott Wood return dev; 718d85937e6SScott Wood } 719d85937e6SScott Wood 72003f04809SIgor Mammedov static DeviceState *ppce500_init_mpic_kvm(const PPCE500MachineClass *pmc, 721fe656ebdSMarkus Armbruster qemu_irq **irqs, Error **errp) 722d85937e6SScott Wood { 723fe656ebdSMarkus Armbruster Error *err = NULL; 724d85937e6SScott Wood DeviceState *dev; 725d85937e6SScott Wood CPUState *cs; 726d85937e6SScott Wood 727dd49c038SAndreas Färber dev = qdev_create(NULL, TYPE_KVM_OPENPIC); 72803f04809SIgor Mammedov qdev_prop_set_uint32(dev, "model", pmc->mpic_version); 729d85937e6SScott Wood 730fe656ebdSMarkus Armbruster object_property_set_bool(OBJECT(dev), true, "realized", &err); 731fe656ebdSMarkus Armbruster if (err) { 732fe656ebdSMarkus Armbruster error_propagate(errp, err); 733fe656ebdSMarkus Armbruster object_unparent(OBJECT(dev)); 734d85937e6SScott Wood return NULL; 735d85937e6SScott Wood } 736d85937e6SScott Wood 737bdc44640SAndreas Färber CPU_FOREACH(cs) { 738d85937e6SScott Wood if (kvm_openpic_connect_vcpu(dev, cs)) { 739d85937e6SScott Wood fprintf(stderr, "%s: failed to connect vcpu to irqchip\n", 740d85937e6SScott Wood __func__); 741d85937e6SScott Wood abort(); 742d85937e6SScott Wood } 743d85937e6SScott Wood } 744d85937e6SScott Wood 745d85937e6SScott Wood return dev; 746d85937e6SScott Wood } 747d85937e6SScott Wood 74803f04809SIgor Mammedov static DeviceState *ppce500_init_mpic(PPCE500MachineState *pms, 749c91c187fSMichael Davidsaver MemoryRegion *ccsr, 750c91c187fSMichael Davidsaver qemu_irq **irqs) 751d85937e6SScott Wood { 75203f04809SIgor Mammedov MachineState *machine = MACHINE(pms); 75303f04809SIgor Mammedov const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(pms); 754d85937e6SScott Wood DeviceState *dev = NULL; 755d85937e6SScott Wood SysBusDevice *s; 756d85937e6SScott Wood 757d85937e6SScott Wood if (kvm_enabled()) { 758fe656ebdSMarkus Armbruster Error *err = NULL; 759d85937e6SScott Wood 760446f16a6SMarcel Apfelbaum if (machine_kernel_irqchip_allowed(machine)) { 76103f04809SIgor Mammedov dev = ppce500_init_mpic_kvm(pmc, irqs, &err); 762d85937e6SScott Wood } 763446f16a6SMarcel Apfelbaum if (machine_kernel_irqchip_required(machine) && !dev) { 764c29b77f9SMarkus Armbruster error_reportf_err(err, 765c29b77f9SMarkus Armbruster "kernel_irqchip requested but unavailable: "); 766fe656ebdSMarkus Armbruster exit(1); 767d85937e6SScott Wood } 768d85937e6SScott Wood } 769d85937e6SScott Wood 770d85937e6SScott Wood if (!dev) { 77103f04809SIgor Mammedov dev = ppce500_init_mpic_qemu(pms, irqs); 772d85937e6SScott Wood } 773d85937e6SScott Wood 774d85937e6SScott Wood s = SYS_BUS_DEVICE(dev); 77582fc73b6SScott Wood memory_region_add_subregion(ccsr, MPC8544_MPIC_REGS_OFFSET, 77682fc73b6SScott Wood s->mmio[0].memory); 77782fc73b6SScott Wood 778c91c187fSMichael Davidsaver return dev; 77982fc73b6SScott Wood } 78082fc73b6SScott Wood 781016f7758SAlexander Graf static void ppce500_power_off(void *opaque, int line, int on) 782016f7758SAlexander Graf { 783016f7758SAlexander Graf if (on) { 784cf83f140SEric Blake qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); 785016f7758SAlexander Graf } 786016f7758SAlexander Graf } 787016f7758SAlexander Graf 78803f04809SIgor Mammedov void ppce500_init(MachineState *machine) 7891db09b84Saurel32 { 79039186d8aSRichard Henderson MemoryRegion *address_space_mem = get_system_memory(); 7912646c133SAvi Kivity MemoryRegion *ram = g_new(MemoryRegion, 1); 79203f04809SIgor Mammedov PPCE500MachineState *pms = PPCE500_MACHINE(machine); 79303f04809SIgor Mammedov const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(machine); 7941db09b84Saurel32 PCIBus *pci_bus; 795e2684c0bSAndreas Färber CPUPPCState *env = NULL; 7963812c71fSAlexander Graf uint64_t loadaddr; 7973812c71fSAlexander Graf hwaddr kernel_base = -1LL; 7983812c71fSAlexander Graf int kernel_size = 0; 7993812c71fSAlexander Graf hwaddr dt_base = 0; 8003812c71fSAlexander Graf hwaddr initrd_base = 0; 8013812c71fSAlexander Graf int initrd_size = 0; 8023812c71fSAlexander Graf hwaddr cur_base = 0; 8033812c71fSAlexander Graf char *filename; 8048d622594SDavid Engraf const char *payload_name; 8058d622594SDavid Engraf bool kernel_as_payload; 8063812c71fSAlexander Graf hwaddr bios_entry = 0; 8078d622594SDavid Engraf target_long payload_size; 8083812c71fSAlexander Graf struct boot_info *boot_info; 8093812c71fSAlexander Graf int dt_size; 81082fc73b6SScott Wood int i; 811d575a6ceSBharat Bhushan /* irq num for pin INTA, INTB, INTC and INTD is 1, 2, 3 and 812d575a6ceSBharat Bhushan * 4 respectively */ 813d575a6ceSBharat Bhushan unsigned int pci_irq_nrs[PCI_NUM_PINS] = {1, 2, 3, 4}; 814c91c187fSMichael Davidsaver qemu_irq **irqs; 815c91c187fSMichael Davidsaver DeviceState *dev, *mpicdev; 816e2684c0bSAndreas Färber CPUPPCState *firstenv = NULL; 8173eddc1beSBharat Bhushan MemoryRegion *ccsr_addr_space; 818dffb1dc2SBharat Bhushan SysBusDevice *s; 8193eddc1beSBharat Bhushan PPCE500CCSRState *ccsr; 8201db09b84Saurel32 821a915249fSAlexander Graf irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *)); 822a915249fSAlexander Graf irqs[0] = g_malloc0(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB); 823e61c36d5SAlexander Graf for (i = 0; i < smp_cpus; i++) { 824397b457dSAndreas Färber PowerPCCPU *cpu; 82555e5c285SAndreas Färber CPUState *cs; 826e61c36d5SAlexander Graf qemu_irq *input; 827397b457dSAndreas Färber 82859e816fdSIgor Mammedov cpu = POWERPC_CPU(cpu_create(machine->cpu_type)); 829397b457dSAndreas Färber env = &cpu->env; 83055e5c285SAndreas Färber cs = CPU(cpu); 8311db09b84Saurel32 83200469dc3SValentin Plotkin if (env->mmu_model != POWERPC_MMU_BOOKE206) { 8336f76b817SAlistair Francis error_report("MMU model %i not supported by this machine", 83400469dc3SValentin Plotkin env->mmu_model); 83500469dc3SValentin Plotkin exit(1); 83600469dc3SValentin Plotkin } 83700469dc3SValentin Plotkin 838e61c36d5SAlexander Graf if (!firstenv) { 839e61c36d5SAlexander Graf firstenv = env; 840e61c36d5SAlexander Graf } 841e61c36d5SAlexander Graf 842a915249fSAlexander Graf irqs[i] = irqs[0] + (i * OPENPIC_OUTPUT_NB); 843a915249fSAlexander Graf input = (qemu_irq *)env->irq_inputs; 844a915249fSAlexander Graf irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT]; 845a915249fSAlexander Graf irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT]; 8466a450df9SAlexander Graf env->spr_cb[SPR_BOOKE_PIR].default_value = cs->cpu_index = i; 84703f04809SIgor Mammedov env->mpic_iack = pmc->ccsrbar_base + MPC8544_MPIC_REGS_OFFSET + 0xa0; 848e61c36d5SAlexander Graf 849a34a92b9SAndreas Färber ppc_booke_timers_init(cpu, 400000000, PPC_TIMER_E500); 8503b989d49SAlexander Graf 8513b989d49SAlexander Graf /* Register reset handler */ 8525c145dacSAlexander Graf if (!i) { 8535c145dacSAlexander Graf /* Primary CPU */ 8545c145dacSAlexander Graf struct boot_info *boot_info; 855e61c36d5SAlexander Graf boot_info = g_malloc0(sizeof(struct boot_info)); 856b3305981SScott Wood qemu_register_reset(ppce500_cpu_reset, cpu); 857e61c36d5SAlexander Graf env->load_info = boot_info; 8585c145dacSAlexander Graf } else { 8595c145dacSAlexander Graf /* Secondary CPUs */ 860b3305981SScott Wood qemu_register_reset(ppce500_cpu_reset_sec, cpu); 8615c145dacSAlexander Graf } 862e61c36d5SAlexander Graf } 863e61c36d5SAlexander Graf 864e61c36d5SAlexander Graf env = firstenv; 8653b989d49SAlexander Graf 8661db09b84Saurel32 /* Fixup Memory size on a alignment boundary */ 8671db09b84Saurel32 ram_size &= ~(RAM_SIZES_ALIGN - 1); 8683ef96221SMarcel Apfelbaum machine->ram_size = ram_size; 8691db09b84Saurel32 8701db09b84Saurel32 /* Register Memory */ 871e938ba0cSShreyas B. Prabhu memory_region_allocate_system_memory(ram, NULL, "mpc8544ds.ram", ram_size); 8722646c133SAvi Kivity memory_region_add_subregion(address_space_mem, 0, ram); 8731db09b84Saurel32 8743eddc1beSBharat Bhushan dev = qdev_create(NULL, "e500-ccsr"); 8753eddc1beSBharat Bhushan object_property_add_child(qdev_get_machine(), "e500-ccsr", 8763eddc1beSBharat Bhushan OBJECT(dev), NULL); 8773eddc1beSBharat Bhushan qdev_init_nofail(dev); 8783eddc1beSBharat Bhushan ccsr = CCSR(dev); 8793eddc1beSBharat Bhushan ccsr_addr_space = &ccsr->ccsr_space; 88003f04809SIgor Mammedov memory_region_add_subregion(address_space_mem, pmc->ccsrbar_base, 8813eddc1beSBharat Bhushan ccsr_addr_space); 882dffb1dc2SBharat Bhushan 88303f04809SIgor Mammedov mpicdev = ppce500_init_mpic(pms, ccsr_addr_space, irqs); 8841db09b84Saurel32 8851db09b84Saurel32 /* Serial */ 8869bca0edbSPeter Maydell if (serial_hd(0)) { 8873eddc1beSBharat Bhushan serial_mm_init(ccsr_addr_space, MPC8544_SERIAL0_REGS_OFFSET, 888c91c187fSMichael Davidsaver 0, qdev_get_gpio_in(mpicdev, 42), 399193, 8899bca0edbSPeter Maydell serial_hd(0), DEVICE_BIG_ENDIAN); 8902d48377aSBlue Swirl } 8911db09b84Saurel32 8929bca0edbSPeter Maydell if (serial_hd(1)) { 8933eddc1beSBharat Bhushan serial_mm_init(ccsr_addr_space, MPC8544_SERIAL1_REGS_OFFSET, 894c91c187fSMichael Davidsaver 0, qdev_get_gpio_in(mpicdev, 42), 399193, 8959bca0edbSPeter Maydell serial_hd(1), DEVICE_BIG_ENDIAN); 8962d48377aSBlue Swirl } 8971db09b84Saurel32 898b0fb8423SAlexander Graf /* General Utility device */ 899dffb1dc2SBharat Bhushan dev = qdev_create(NULL, "mpc8544-guts"); 900dffb1dc2SBharat Bhushan qdev_init_nofail(dev); 901dffb1dc2SBharat Bhushan s = SYS_BUS_DEVICE(dev); 9023eddc1beSBharat Bhushan memory_region_add_subregion(ccsr_addr_space, MPC8544_UTIL_OFFSET, 903dffb1dc2SBharat Bhushan sysbus_mmio_get_region(s, 0)); 904b0fb8423SAlexander Graf 9051db09b84Saurel32 /* PCI */ 906dffb1dc2SBharat Bhushan dev = qdev_create(NULL, "e500-pcihost"); 907e75ce32aSMichael Davidsaver object_property_add_child(qdev_get_machine(), "pci-host", OBJECT(dev), 908e75ce32aSMichael Davidsaver &error_abort); 90903f04809SIgor Mammedov qdev_prop_set_uint32(dev, "first_slot", pmc->pci_first_slot); 9103016dca0SBharat Bhushan qdev_prop_set_uint32(dev, "first_pin_irq", pci_irq_nrs[0]); 911dffb1dc2SBharat Bhushan qdev_init_nofail(dev); 912dffb1dc2SBharat Bhushan s = SYS_BUS_DEVICE(dev); 913d575a6ceSBharat Bhushan for (i = 0; i < PCI_NUM_PINS; i++) { 914c91c187fSMichael Davidsaver sysbus_connect_irq(s, i, qdev_get_gpio_in(mpicdev, pci_irq_nrs[i])); 915d575a6ceSBharat Bhushan } 916d575a6ceSBharat Bhushan 9173eddc1beSBharat Bhushan memory_region_add_subregion(ccsr_addr_space, MPC8544_PCI_REGS_OFFSET, 918dffb1dc2SBharat Bhushan sysbus_mmio_get_region(s, 0)); 919dffb1dc2SBharat Bhushan 920d461e3b9SAlexander Graf pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0"); 9211db09b84Saurel32 if (!pci_bus) 9221db09b84Saurel32 printf("couldn't create PCI controller!\n"); 9231db09b84Saurel32 9241db09b84Saurel32 if (pci_bus) { 9251db09b84Saurel32 /* Register network interfaces. */ 9261db09b84Saurel32 for (i = 0; i < nb_nics; i++) { 92752310c3fSPaolo Bonzini pci_nic_init_nofail(&nd_table[i], pci_bus, "virtio-net-pci", NULL); 9281db09b84Saurel32 } 9291db09b84Saurel32 } 9301db09b84Saurel32 9315c145dacSAlexander Graf /* Register spinning region */ 93203f04809SIgor Mammedov sysbus_create_simple("e500-spin", pmc->spin_base, NULL); 9335c145dacSAlexander Graf 93403f04809SIgor Mammedov if (pmc->has_mpc8xxx_gpio) { 935016f7758SAlexander Graf qemu_irq poweroff_irq; 936016f7758SAlexander Graf 937b88e77f4SAlexander Graf dev = qdev_create(NULL, "mpc8xxx_gpio"); 938b88e77f4SAlexander Graf s = SYS_BUS_DEVICE(dev); 939b88e77f4SAlexander Graf qdev_init_nofail(dev); 940c91c187fSMichael Davidsaver sysbus_connect_irq(s, 0, qdev_get_gpio_in(mpicdev, MPC8XXX_GPIO_IRQ)); 941b88e77f4SAlexander Graf memory_region_add_subregion(ccsr_addr_space, MPC8XXX_GPIO_OFFSET, 942b88e77f4SAlexander Graf sysbus_mmio_get_region(s, 0)); 943016f7758SAlexander Graf 944016f7758SAlexander Graf /* Power Off GPIO at Pin 0 */ 945016f7758SAlexander Graf poweroff_irq = qemu_allocate_irq(ppce500_power_off, NULL, 0); 946016f7758SAlexander Graf qdev_connect_gpio_out(dev, 0, poweroff_irq); 947b88e77f4SAlexander Graf } 948b88e77f4SAlexander Graf 949f7087343SAlexander Graf /* Platform Bus Device */ 95003f04809SIgor Mammedov if (pmc->has_platform_bus) { 951f7087343SAlexander Graf dev = qdev_create(NULL, TYPE_PLATFORM_BUS_DEVICE); 952f7087343SAlexander Graf dev->id = TYPE_PLATFORM_BUS_DEVICE; 95303f04809SIgor Mammedov qdev_prop_set_uint32(dev, "num_irqs", pmc->platform_bus_num_irqs); 95403f04809SIgor Mammedov qdev_prop_set_uint32(dev, "mmio_size", pmc->platform_bus_size); 955f7087343SAlexander Graf qdev_init_nofail(dev); 956f7087343SAlexander Graf s = SYS_BUS_DEVICE(dev); 957f7087343SAlexander Graf 95803f04809SIgor Mammedov for (i = 0; i < pmc->platform_bus_num_irqs; i++) { 95903f04809SIgor Mammedov int irqn = pmc->platform_bus_first_irq + i; 960c91c187fSMichael Davidsaver sysbus_connect_irq(s, i, qdev_get_gpio_in(mpicdev, irqn)); 961f7087343SAlexander Graf } 962f7087343SAlexander Graf 963f7087343SAlexander Graf memory_region_add_subregion(address_space_mem, 96403f04809SIgor Mammedov pmc->platform_bus_base, 965f7087343SAlexander Graf sysbus_mmio_get_region(s, 0)); 966f7087343SAlexander Graf } 967f7087343SAlexander Graf 9688d622594SDavid Engraf /* 9698d622594SDavid Engraf * Smart firmware defaults ahead! 9708d622594SDavid Engraf * 9718d622594SDavid Engraf * We follow the following table to select which payload we execute. 9728d622594SDavid Engraf * 9738d622594SDavid Engraf * -kernel | -bios | payload 9748d622594SDavid Engraf * ---------+-------+--------- 9758d622594SDavid Engraf * N | Y | u-boot 9768d622594SDavid Engraf * N | N | u-boot 9778d622594SDavid Engraf * Y | Y | u-boot 9788d622594SDavid Engraf * Y | N | kernel 9798d622594SDavid Engraf * 9808d622594SDavid Engraf * This ensures backwards compatibility with how we used to expose 9818d622594SDavid Engraf * -kernel to users but allows them to run through u-boot as well. 9828d622594SDavid Engraf */ 9838d622594SDavid Engraf kernel_as_payload = false; 9848d622594SDavid Engraf if (bios_name == NULL) { 9853ef96221SMarcel Apfelbaum if (machine->kernel_filename) { 9868d622594SDavid Engraf payload_name = machine->kernel_filename; 9878d622594SDavid Engraf kernel_as_payload = true; 9888d622594SDavid Engraf } else { 9898d622594SDavid Engraf payload_name = "u-boot.e500"; 9908d622594SDavid Engraf } 9918d622594SDavid Engraf } else { 9928d622594SDavid Engraf payload_name = bios_name; 9938d622594SDavid Engraf } 9948d622594SDavid Engraf 9958d622594SDavid Engraf filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, payload_name); 9968d622594SDavid Engraf 9978d622594SDavid Engraf payload_size = load_elf(filename, NULL, NULL, &bios_entry, &loadaddr, NULL, 9988d622594SDavid Engraf 1, PPC_ELF_MACHINE, 0, 0); 9998d622594SDavid Engraf if (payload_size < 0) { 10008d622594SDavid Engraf /* 10018d622594SDavid Engraf * Hrm. No ELF image? Try a uImage, maybe someone is giving us an 10028d622594SDavid Engraf * ePAPR compliant kernel 10038d622594SDavid Engraf */ 10048d622594SDavid Engraf payload_size = load_uimage(filename, &bios_entry, &loadaddr, NULL, 10058d622594SDavid Engraf NULL, NULL); 10068d622594SDavid Engraf if (payload_size < 0) { 10078d622594SDavid Engraf error_report("qemu: could not load firmware '%s'", filename); 10088d622594SDavid Engraf exit(1); 10098d622594SDavid Engraf } 10108d622594SDavid Engraf } 10118d622594SDavid Engraf 10128d622594SDavid Engraf g_free(filename); 10138d622594SDavid Engraf 10148d622594SDavid Engraf if (kernel_as_payload) { 10158d622594SDavid Engraf kernel_base = loadaddr; 10168d622594SDavid Engraf kernel_size = payload_size; 10178d622594SDavid Engraf } 10188d622594SDavid Engraf 10198d622594SDavid Engraf cur_base = loadaddr + payload_size; 1020b4a5f24aSDavid Engraf if (cur_base < (32 * 1024 * 1024)) { 1021b4a5f24aSDavid Engraf /* u-boot occupies memory up to 32MB, so load blobs above */ 1022b4a5f24aSDavid Engraf cur_base = (32 * 1024 * 1024); 1023b4a5f24aSDavid Engraf } 10248d622594SDavid Engraf 10258d622594SDavid Engraf /* Load bare kernel only if no bios/u-boot has been provided */ 10268d622594SDavid Engraf if (machine->kernel_filename && !kernel_as_payload) { 10273812c71fSAlexander Graf kernel_base = cur_base; 10283812c71fSAlexander Graf kernel_size = load_image_targphys(machine->kernel_filename, 10293812c71fSAlexander Graf cur_base, 10303812c71fSAlexander Graf ram_size - cur_base); 10311db09b84Saurel32 if (kernel_size < 0) { 10326f76b817SAlistair Francis error_report("could not load kernel '%s'", 10333ef96221SMarcel Apfelbaum machine->kernel_filename); 10341db09b84Saurel32 exit(1); 10351db09b84Saurel32 } 1036528e536eSAlexander Graf 10373812c71fSAlexander Graf cur_base += kernel_size; 10381db09b84Saurel32 } 10391db09b84Saurel32 10401db09b84Saurel32 /* Load initrd. */ 10413ef96221SMarcel Apfelbaum if (machine->initrd_filename) { 1042528e536eSAlexander Graf initrd_base = (cur_base + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK; 10433ef96221SMarcel Apfelbaum initrd_size = load_image_targphys(machine->initrd_filename, initrd_base, 1044d7585251Spbrook ram_size - initrd_base); 10451db09b84Saurel32 10461db09b84Saurel32 if (initrd_size < 0) { 10476f76b817SAlistair Francis error_report("could not load initial ram disk '%s'", 10483ef96221SMarcel Apfelbaum machine->initrd_filename); 10491db09b84Saurel32 exit(1); 10501db09b84Saurel32 } 1051528e536eSAlexander Graf 1052528e536eSAlexander Graf cur_base = initrd_base + initrd_size; 10531db09b84Saurel32 } 10541db09b84Saurel32 10553812c71fSAlexander Graf /* 10568d622594SDavid Engraf * Reserve space for dtb behind the kernel image because Linux has a bug 10578d622594SDavid Engraf * where it can only handle the dtb if it's within the first 64MB of where 10588d622594SDavid Engraf * <kernel> starts. dtb cannot not reach initrd_base because INITRD_LOAD_PAD 10598d622594SDavid Engraf * ensures enough space between kernel and initrd. 10603812c71fSAlexander Graf */ 10618d622594SDavid Engraf dt_base = (loadaddr + payload_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK; 10628d622594SDavid Engraf if (dt_base + DTB_MAX_SIZE > ram_size) { 10638d622594SDavid Engraf error_report("qemu: not enough memory for device tree"); 10643812c71fSAlexander Graf exit(1); 10653812c71fSAlexander Graf } 10665c145dacSAlexander Graf 106703f04809SIgor Mammedov dt_size = ppce500_prep_device_tree(pms, dt_base, 1068903585deSAlexander Graf initrd_base, initrd_size, 10693812c71fSAlexander Graf kernel_base, kernel_size); 1070cba2026aSAlexander Graf if (dt_size < 0) { 10716f76b817SAlistair Francis error_report("couldn't load device tree"); 10721db09b84Saurel32 exit(1); 10731db09b84Saurel32 } 1074b8dec144SAlexander Graf assert(dt_size < DTB_MAX_SIZE); 10751db09b84Saurel32 1076e61c36d5SAlexander Graf boot_info = env->load_info; 10773812c71fSAlexander Graf boot_info->entry = bios_entry; 10783b989d49SAlexander Graf boot_info->dt_base = dt_base; 1079cba2026aSAlexander Graf boot_info->dt_size = dt_size; 10801db09b84Saurel32 } 10813eddc1beSBharat Bhushan 1082d0c2b0d0Sxiaoqiang zhao static void e500_ccsr_initfn(Object *obj) 10833eddc1beSBharat Bhushan { 1084d0c2b0d0Sxiaoqiang zhao PPCE500CCSRState *ccsr = CCSR(obj); 1085d0c2b0d0Sxiaoqiang zhao memory_region_init(&ccsr->ccsr_space, obj, "e500-ccsr", 10863eddc1beSBharat Bhushan MPC8544_CCSRBAR_SIZE); 10873eddc1beSBharat Bhushan } 10883eddc1beSBharat Bhushan 10893eddc1beSBharat Bhushan static const TypeInfo e500_ccsr_info = { 10903eddc1beSBharat Bhushan .name = TYPE_CCSR, 10913eddc1beSBharat Bhushan .parent = TYPE_SYS_BUS_DEVICE, 10923eddc1beSBharat Bhushan .instance_size = sizeof(PPCE500CCSRState), 1093d0c2b0d0Sxiaoqiang zhao .instance_init = e500_ccsr_initfn, 10943eddc1beSBharat Bhushan }; 10953eddc1beSBharat Bhushan 109603f04809SIgor Mammedov static const TypeInfo ppce500_info = { 109703f04809SIgor Mammedov .name = TYPE_PPCE500_MACHINE, 109803f04809SIgor Mammedov .parent = TYPE_MACHINE, 109903f04809SIgor Mammedov .abstract = true, 110003f04809SIgor Mammedov .class_size = sizeof(PPCE500MachineClass), 110103f04809SIgor Mammedov }; 110203f04809SIgor Mammedov 11033eddc1beSBharat Bhushan static void e500_register_types(void) 11043eddc1beSBharat Bhushan { 11053eddc1beSBharat Bhushan type_register_static(&e500_ccsr_info); 110603f04809SIgor Mammedov type_register_static(&ppce500_info); 11073eddc1beSBharat Bhushan } 11083eddc1beSBharat Bhushan 11093eddc1beSBharat Bhushan type_init(e500_register_types) 1110