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 { 109a053a7ceSAlexander Graf char ser[128]; 110a053a7ceSAlexander Graf 111a053a7ceSAlexander Graf snprintf(ser, sizeof(ser), "%s/serial@%llx", soc, offset); 1125a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, ser); 1135a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, ser, "device_type", "serial"); 1145a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, ser, "compatible", "ns16550"); 1155a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, ser, "reg", offset, 0x100); 1165a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, ser, "cell-index", idx); 1175a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, ser, "clock-frequency", 0); 1185a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, ser, "interrupts", 42, 2); 1195a4348d1SPeter Crosthwaite qemu_fdt_setprop_phandle(fdt, ser, "interrupt-parent", mpic); 1205a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, "/aliases", alias, ser); 121a053a7ceSAlexander Graf 122a053a7ceSAlexander Graf if (defcon) { 123*90ee4e01SNikunj A Dadhania /* 124*90ee4e01SNikunj A Dadhania * "linux,stdout-path" and "stdout" properties are deprecated by linux 125*90ee4e01SNikunj A Dadhania * kernel. New platforms should only use the "stdout-path" property. Set 126*90ee4e01SNikunj A Dadhania * the new property and continue using older property to remain 127*90ee4e01SNikunj A Dadhania * compatible with the existing firmware. 128*90ee4e01SNikunj A Dadhania */ 1295a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, "/chosen", "linux,stdout-path", ser); 130*90ee4e01SNikunj A Dadhania qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", ser); 131a053a7ceSAlexander Graf } 132a053a7ceSAlexander Graf } 133a053a7ceSAlexander Graf 134b88e77f4SAlexander Graf static void create_dt_mpc8xxx_gpio(void *fdt, const char *soc, const char *mpic) 135b88e77f4SAlexander Graf { 136b88e77f4SAlexander Graf hwaddr mmio0 = MPC8XXX_GPIO_OFFSET; 137b88e77f4SAlexander Graf int irq0 = MPC8XXX_GPIO_IRQ; 138b88e77f4SAlexander Graf gchar *node = g_strdup_printf("%s/gpio@%"PRIx64, soc, mmio0); 139016f7758SAlexander Graf gchar *poweroff = g_strdup_printf("%s/power-off", soc); 140016f7758SAlexander Graf int gpio_ph; 141b88e77f4SAlexander Graf 142b88e77f4SAlexander Graf qemu_fdt_add_subnode(fdt, node); 143b88e77f4SAlexander Graf qemu_fdt_setprop_string(fdt, node, "compatible", "fsl,qoriq-gpio"); 144b88e77f4SAlexander Graf qemu_fdt_setprop_cells(fdt, node, "reg", mmio0, 0x1000); 145b88e77f4SAlexander Graf qemu_fdt_setprop_cells(fdt, node, "interrupts", irq0, 0x2); 146b88e77f4SAlexander Graf qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", mpic); 147b88e77f4SAlexander Graf qemu_fdt_setprop_cells(fdt, node, "#gpio-cells", 2); 148b88e77f4SAlexander Graf qemu_fdt_setprop(fdt, node, "gpio-controller", NULL, 0); 149016f7758SAlexander Graf gpio_ph = qemu_fdt_alloc_phandle(fdt); 150016f7758SAlexander Graf qemu_fdt_setprop_cell(fdt, node, "phandle", gpio_ph); 151016f7758SAlexander Graf qemu_fdt_setprop_cell(fdt, node, "linux,phandle", gpio_ph); 152016f7758SAlexander Graf 153016f7758SAlexander Graf /* Power Off Pin */ 154016f7758SAlexander Graf qemu_fdt_add_subnode(fdt, poweroff); 155016f7758SAlexander Graf qemu_fdt_setprop_string(fdt, poweroff, "compatible", "gpio-poweroff"); 156016f7758SAlexander Graf qemu_fdt_setprop_cells(fdt, poweroff, "gpios", gpio_ph, 0, 0); 157b88e77f4SAlexander Graf 158b88e77f4SAlexander Graf g_free(node); 159016f7758SAlexander Graf g_free(poweroff); 160b88e77f4SAlexander Graf } 161b88e77f4SAlexander Graf 162f7087343SAlexander Graf typedef struct PlatformDevtreeData { 163f7087343SAlexander Graf void *fdt; 164f7087343SAlexander Graf const char *mpic; 165f7087343SAlexander Graf int irq_start; 166f7087343SAlexander Graf const char *node; 167f7087343SAlexander Graf PlatformBusDevice *pbus; 168f7087343SAlexander Graf } PlatformDevtreeData; 169f7087343SAlexander Graf 170fdfb7f2cSAlexander Graf static int create_devtree_etsec(SysBusDevice *sbdev, PlatformDevtreeData *data) 171fdfb7f2cSAlexander Graf { 172fdfb7f2cSAlexander Graf eTSEC *etsec = ETSEC_COMMON(sbdev); 173fdfb7f2cSAlexander Graf PlatformBusDevice *pbus = data->pbus; 174fdfb7f2cSAlexander Graf hwaddr mmio0 = platform_bus_get_mmio_addr(pbus, sbdev, 0); 175fdfb7f2cSAlexander Graf int irq0 = platform_bus_get_irqn(pbus, sbdev, 0); 176fdfb7f2cSAlexander Graf int irq1 = platform_bus_get_irqn(pbus, sbdev, 1); 177fdfb7f2cSAlexander Graf int irq2 = platform_bus_get_irqn(pbus, sbdev, 2); 178fdfb7f2cSAlexander Graf gchar *node = g_strdup_printf("/platform/ethernet@%"PRIx64, mmio0); 179fdfb7f2cSAlexander Graf gchar *group = g_strdup_printf("%s/queue-group", node); 180fdfb7f2cSAlexander Graf void *fdt = data->fdt; 181fdfb7f2cSAlexander Graf 182fdfb7f2cSAlexander Graf assert((int64_t)mmio0 >= 0); 183fdfb7f2cSAlexander Graf assert(irq0 >= 0); 184fdfb7f2cSAlexander Graf assert(irq1 >= 0); 185fdfb7f2cSAlexander Graf assert(irq2 >= 0); 186fdfb7f2cSAlexander Graf 187fdfb7f2cSAlexander Graf qemu_fdt_add_subnode(fdt, node); 188fdfb7f2cSAlexander Graf qemu_fdt_setprop_string(fdt, node, "device_type", "network"); 189fdfb7f2cSAlexander Graf qemu_fdt_setprop_string(fdt, node, "compatible", "fsl,etsec2"); 190fdfb7f2cSAlexander Graf qemu_fdt_setprop_string(fdt, node, "model", "eTSEC"); 191fdfb7f2cSAlexander Graf qemu_fdt_setprop(fdt, node, "local-mac-address", etsec->conf.macaddr.a, 6); 192fdfb7f2cSAlexander Graf qemu_fdt_setprop_cells(fdt, node, "fixed-link", 0, 1, 1000, 0, 0); 193fdfb7f2cSAlexander Graf 194fdfb7f2cSAlexander Graf qemu_fdt_add_subnode(fdt, group); 195fdfb7f2cSAlexander Graf qemu_fdt_setprop_cells(fdt, group, "reg", mmio0, 0x1000); 196fdfb7f2cSAlexander Graf qemu_fdt_setprop_cells(fdt, group, "interrupts", 197fdfb7f2cSAlexander Graf data->irq_start + irq0, 0x2, 198fdfb7f2cSAlexander Graf data->irq_start + irq1, 0x2, 199fdfb7f2cSAlexander Graf data->irq_start + irq2, 0x2); 200fdfb7f2cSAlexander Graf 201fdfb7f2cSAlexander Graf g_free(node); 202fdfb7f2cSAlexander Graf g_free(group); 203fdfb7f2cSAlexander Graf 204fdfb7f2cSAlexander Graf return 0; 205fdfb7f2cSAlexander Graf } 206fdfb7f2cSAlexander Graf 2074f01a637SDavid Gibson static void sysbus_device_create_devtree(SysBusDevice *sbdev, void *opaque) 208f7087343SAlexander Graf { 209f7087343SAlexander Graf PlatformDevtreeData *data = opaque; 210f7087343SAlexander Graf bool matched = false; 211f7087343SAlexander Graf 212fdfb7f2cSAlexander Graf if (object_dynamic_cast(OBJECT(sbdev), TYPE_ETSEC_COMMON)) { 213fdfb7f2cSAlexander Graf create_devtree_etsec(sbdev, data); 214fdfb7f2cSAlexander Graf matched = true; 215fdfb7f2cSAlexander Graf } 216fdfb7f2cSAlexander Graf 217f7087343SAlexander Graf if (!matched) { 218f7087343SAlexander Graf error_report("Device %s is not supported by this machine yet.", 219f7087343SAlexander Graf qdev_fw_name(DEVICE(sbdev))); 220f7087343SAlexander Graf exit(1); 221f7087343SAlexander Graf } 222f7087343SAlexander Graf } 223f7087343SAlexander Graf 224f7087343SAlexander Graf static void platform_bus_create_devtree(PPCE500Params *params, void *fdt, 225f7087343SAlexander Graf const char *mpic) 226f7087343SAlexander Graf { 227f7087343SAlexander Graf gchar *node = g_strdup_printf("/platform@%"PRIx64, params->platform_bus_base); 228f7087343SAlexander Graf const char platcomp[] = "qemu,platform\0simple-bus"; 229f7087343SAlexander Graf uint64_t addr = params->platform_bus_base; 230f7087343SAlexander Graf uint64_t size = params->platform_bus_size; 231f7087343SAlexander Graf int irq_start = params->platform_bus_first_irq; 232f7087343SAlexander Graf PlatformBusDevice *pbus; 233f7087343SAlexander Graf DeviceState *dev; 234f7087343SAlexander Graf 235f7087343SAlexander Graf /* Create a /platform node that we can put all devices into */ 236f7087343SAlexander Graf 237f7087343SAlexander Graf qemu_fdt_add_subnode(fdt, node); 238f7087343SAlexander Graf qemu_fdt_setprop(fdt, node, "compatible", platcomp, sizeof(platcomp)); 239f7087343SAlexander Graf 240f7087343SAlexander Graf /* Our platform bus region is less than 32bit big, so 1 cell is enough for 241f7087343SAlexander Graf address and size */ 242f7087343SAlexander Graf qemu_fdt_setprop_cells(fdt, node, "#size-cells", 1); 243f7087343SAlexander Graf qemu_fdt_setprop_cells(fdt, node, "#address-cells", 1); 244f7087343SAlexander Graf qemu_fdt_setprop_cells(fdt, node, "ranges", 0, addr >> 32, addr, size); 245f7087343SAlexander Graf 246f7087343SAlexander Graf qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", mpic); 247f7087343SAlexander Graf 248f7087343SAlexander Graf dev = qdev_find_recursive(sysbus_get_default(), TYPE_PLATFORM_BUS_DEVICE); 249f7087343SAlexander Graf pbus = PLATFORM_BUS_DEVICE(dev); 250f7087343SAlexander Graf 251f7087343SAlexander Graf /* We can only create dt nodes for dynamic devices when they're ready */ 252f7087343SAlexander Graf if (pbus->done_gathering) { 253f7087343SAlexander Graf PlatformDevtreeData data = { 254f7087343SAlexander Graf .fdt = fdt, 255f7087343SAlexander Graf .mpic = mpic, 256f7087343SAlexander Graf .irq_start = irq_start, 257f7087343SAlexander Graf .node = node, 258f7087343SAlexander Graf .pbus = pbus, 259f7087343SAlexander Graf }; 260f7087343SAlexander Graf 261f7087343SAlexander Graf /* Loop through all dynamic sysbus devices and create nodes for them */ 262f7087343SAlexander Graf foreach_dynamic_sysbus_device(sysbus_device_create_devtree, &data); 263f7087343SAlexander Graf } 264f7087343SAlexander Graf 265f7087343SAlexander Graf g_free(node); 266f7087343SAlexander Graf } 267f7087343SAlexander Graf 2683ef96221SMarcel Apfelbaum static int ppce500_load_device_tree(MachineState *machine, 269e6eaabebSScott Wood PPCE500Params *params, 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 { 27728290f37SAlexander Graf CPUPPCState *env = first_cpu->env_ptr; 278dbf916d8SAurelien Jarno int ret = -1; 2793ef96221SMarcel Apfelbaum uint64_t mem_reg_property[] = { 0, cpu_to_be64(machine->ram_size) }; 2807ec632b4Spbrook int fdt_size; 281dbf916d8SAurelien Jarno void *fdt; 2825de6b46dSAlexander Graf uint8_t hypercall[16]; 283911d6e7aSAlexander Graf uint32_t clock_freq = 400000000; 284911d6e7aSAlexander Graf uint32_t tb_freq = 400000000; 285621d05e3SAlexander Graf int i; 286ebb9518aSAlexander Graf char compatible_sb[] = "fsl,mpc8544-immr\0simple-bus"; 2875da96624SAlexander Graf char soc[128]; 28819ac9deaSAlexander Graf char mpic[128]; 28919ac9deaSAlexander Graf uint32_t mpic_ph; 290a911b7a9SAlexander Graf uint32_t msi_ph; 291f5038483SAlexander Graf char gutil[128]; 2920dbc0798SAlexander Graf char pci[128]; 293a911b7a9SAlexander Graf char msi[128]; 294347dd79dSAlexander Graf uint32_t *pci_map = NULL; 295347dd79dSAlexander Graf int len; 2963627757eSAlexander Graf uint32_t pci_ranges[14] = 2973627757eSAlexander Graf { 298cb3778a0SAlexander Graf 0x2000000, 0x0, params->pci_mmio_bus_base, 299cb3778a0SAlexander Graf params->pci_mmio_base >> 32, params->pci_mmio_base, 3003627757eSAlexander Graf 0x0, 0x20000000, 3013627757eSAlexander Graf 3023627757eSAlexander Graf 0x1000000, 0x0, 0x0, 3032eaaac1fSAlexander Graf params->pci_pio_base >> 32, params->pci_pio_base, 3043627757eSAlexander Graf 0x0, 0x10000, 3053627757eSAlexander Graf }; 3062ff3de68SMarkus Armbruster QemuOpts *machine_opts = qemu_get_machine_opts(); 3072ff3de68SMarkus Armbruster const char *dtb_file = qemu_opt_get(machine_opts, "dtb"); 3082ff3de68SMarkus Armbruster const char *toplevel_compat = qemu_opt_get(machine_opts, "dt_compatible"); 309d1b93565SAlexander Graf 310d1b93565SAlexander Graf if (dtb_file) { 311d1b93565SAlexander Graf char *filename; 312d1b93565SAlexander Graf filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_file); 313d1b93565SAlexander Graf if (!filename) { 314d1b93565SAlexander Graf goto out; 315d1b93565SAlexander Graf } 316d1b93565SAlexander Graf 317d1b93565SAlexander Graf fdt = load_device_tree(filename, &fdt_size); 3182343dd11SMichael Tokarev g_free(filename); 319d1b93565SAlexander Graf if (!fdt) { 320d1b93565SAlexander Graf goto out; 321d1b93565SAlexander Graf } 322d1b93565SAlexander Graf goto done; 323d1b93565SAlexander Graf } 3241db09b84Saurel32 3252636fcb6SAlexander Graf fdt = create_device_tree(&fdt_size); 3265cea8590SPaul Brook if (fdt == NULL) { 3275cea8590SPaul Brook goto out; 3285cea8590SPaul Brook } 3291db09b84Saurel32 3301db09b84Saurel32 /* Manipulate device tree in memory. */ 3315a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 2); 3325a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 2); 33351b852b7SAlexander Graf 3345a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, "/memory"); 3355a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, "/memory", "device_type", "memory"); 3365a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, "/memory", "reg", mem_reg_property, 3371db09b84Saurel32 sizeof(mem_reg_property)); 3381db09b84Saurel32 3395a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, "/chosen"); 3403b989d49SAlexander Graf if (initrd_size) { 3415a4348d1SPeter Crosthwaite ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start", 3421db09b84Saurel32 initrd_base); 3433b989d49SAlexander Graf if (ret < 0) { 3441db09b84Saurel32 fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n"); 3453b989d49SAlexander Graf } 3461db09b84Saurel32 3475a4348d1SPeter Crosthwaite ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end", 3481db09b84Saurel32 (initrd_base + initrd_size)); 3493b989d49SAlexander Graf if (ret < 0) { 3501db09b84Saurel32 fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n"); 3513b989d49SAlexander Graf } 352903585deSAlexander Graf 353903585deSAlexander Graf } 354903585deSAlexander Graf 355903585deSAlexander Graf if (kernel_base != -1ULL) { 356903585deSAlexander Graf qemu_fdt_setprop_cells(fdt, "/chosen", "qemu,boot-kernel", 357903585deSAlexander Graf kernel_base >> 32, kernel_base, 358903585deSAlexander Graf kernel_size >> 32, kernel_size); 3593b989d49SAlexander Graf } 3601db09b84Saurel32 3615a4348d1SPeter Crosthwaite ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", 3623ef96221SMarcel Apfelbaum machine->kernel_cmdline); 3631db09b84Saurel32 if (ret < 0) 3641db09b84Saurel32 fprintf(stderr, "couldn't set /chosen/bootargs\n"); 3651db09b84Saurel32 3661db09b84Saurel32 if (kvm_enabled()) { 367911d6e7aSAlexander Graf /* Read out host's frequencies */ 368911d6e7aSAlexander Graf clock_freq = kvmppc_get_clockfreq(); 369911d6e7aSAlexander Graf tb_freq = kvmppc_get_tbfreq(); 3705de6b46dSAlexander Graf 3715de6b46dSAlexander Graf /* indicate KVM hypercall interface */ 3725a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, "/hypervisor"); 3735a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, "/hypervisor", "compatible", 3745de6b46dSAlexander Graf "linux,kvm"); 3755de6b46dSAlexander Graf kvmppc_get_hypercall(env, hypercall, sizeof(hypercall)); 3765a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, "/hypervisor", "hcall-instructions", 3775de6b46dSAlexander Graf hypercall, sizeof(hypercall)); 3781a61a9aeSStuart Yoder /* if KVM supports the idle hcall, set property indicating this */ 3791a61a9aeSStuart Yoder if (kvmppc_get_hasidle(env)) { 3805a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, "/hypervisor", "has-idle", NULL, 0); 3811a61a9aeSStuart Yoder } 3821db09b84Saurel32 } 3831db09b84Saurel32 384625e665bSAlexander Graf /* Create CPU nodes */ 3855a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, "/cpus"); 3865a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 1); 3875a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0); 388625e665bSAlexander Graf 3891e3debf0SAlexander Graf /* We need to generate the cpu nodes in reverse order, so Linux can pick 3901e3debf0SAlexander Graf the first node as boot node and be happy */ 3911e3debf0SAlexander Graf for (i = smp_cpus - 1; i >= 0; i--) { 392440c8152SAndreas Färber CPUState *cpu; 393621d05e3SAlexander Graf char cpu_name[128]; 3942eaaac1fSAlexander Graf uint64_t cpu_release_addr = params->spin_base + (i * 0x20); 39510f25a46SAlexander Graf 396440c8152SAndreas Färber cpu = qemu_get_cpu(i); 39755e5c285SAndreas Färber if (cpu == NULL) { 3981e3debf0SAlexander Graf continue; 3991e3debf0SAlexander Graf } 400440c8152SAndreas Färber env = cpu->env_ptr; 4011e3debf0SAlexander Graf 4026d536570SSam Bobroff snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x", i); 4035a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, cpu_name); 4045a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq); 4055a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq); 4065a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, cpu_name, "device_type", "cpu"); 4076d536570SSam Bobroff qemu_fdt_setprop_cell(fdt, cpu_name, "reg", i); 4085a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-line-size", 4091e3debf0SAlexander Graf env->dcache_line_size); 4105a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-line-size", 4111e3debf0SAlexander Graf env->icache_line_size); 4125a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-size", 0x8000); 4135a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-size", 0x8000); 4145a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "bus-frequency", 0); 41555e5c285SAndreas Färber if (cpu->cpu_index) { 4165a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, cpu_name, "status", "disabled"); 4175a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, cpu_name, "enable-method", 4185a4348d1SPeter Crosthwaite "spin-table"); 4195a4348d1SPeter Crosthwaite qemu_fdt_setprop_u64(fdt, cpu_name, "cpu-release-addr", 4201d2e5c52SAlexander Graf cpu_release_addr); 4211e3debf0SAlexander Graf } else { 4225a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, cpu_name, "status", "okay"); 4231e3debf0SAlexander Graf } 4241db09b84Saurel32 } 4251db09b84Saurel32 4265a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, "/aliases"); 4275da96624SAlexander Graf /* XXX These should go into their respective devices' code */ 4282eaaac1fSAlexander Graf snprintf(soc, sizeof(soc), "/soc@%"PRIx64, params->ccsrbar_base); 4295a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, soc); 4305a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, soc, "device_type", "soc"); 4315a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, soc, "compatible", compatible_sb, 432ebb9518aSAlexander Graf sizeof(compatible_sb)); 4335a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, soc, "#address-cells", 1); 4345a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, soc, "#size-cells", 1); 4355a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, soc, "ranges", 0x0, 4362eaaac1fSAlexander Graf params->ccsrbar_base >> 32, params->ccsrbar_base, 4375da96624SAlexander Graf MPC8544_CCSRBAR_SIZE); 4385da96624SAlexander Graf /* XXX should contain a reasonable value */ 4395a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, soc, "bus-frequency", 0); 4405da96624SAlexander Graf 441dffb1dc2SBharat Bhushan snprintf(mpic, sizeof(mpic), "%s/pic@%llx", soc, MPC8544_MPIC_REGS_OFFSET); 4425a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, mpic); 4435a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, mpic, "device_type", "open-pic"); 4445a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, mpic, "compatible", "fsl,mpic"); 4455a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_OFFSET, 446dffb1dc2SBharat Bhushan 0x40000); 4475a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, mpic, "#address-cells", 0); 4485a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, mpic, "#interrupt-cells", 2); 4495a4348d1SPeter Crosthwaite mpic_ph = qemu_fdt_alloc_phandle(fdt); 4505a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, mpic, "phandle", mpic_ph); 4515a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, mpic, "linux,phandle", mpic_ph); 4525a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, mpic, "interrupt-controller", NULL, 0); 45319ac9deaSAlexander Graf 4540cfc6e8dSAlexander Graf /* 4550cfc6e8dSAlexander Graf * We have to generate ser1 first, because Linux takes the first 4560cfc6e8dSAlexander Graf * device it finds in the dt as serial output device. And we generate 4570cfc6e8dSAlexander Graf * devices in reverse order to the dt. 4580cfc6e8dSAlexander Graf */ 45979c0ff2cSAlexander Graf if (serial_hds[1]) { 460dffb1dc2SBharat Bhushan dt_serial_create(fdt, MPC8544_SERIAL1_REGS_OFFSET, 461a053a7ceSAlexander Graf soc, mpic, "serial1", 1, false); 46279c0ff2cSAlexander Graf } 46379c0ff2cSAlexander Graf 46479c0ff2cSAlexander Graf if (serial_hds[0]) { 465dffb1dc2SBharat Bhushan dt_serial_create(fdt, MPC8544_SERIAL0_REGS_OFFSET, 466a053a7ceSAlexander Graf soc, mpic, "serial0", 0, true); 46779c0ff2cSAlexander Graf } 4680cfc6e8dSAlexander Graf 469ed2bc496SAlexander Graf snprintf(gutil, sizeof(gutil), "%s/global-utilities@%llx", soc, 470dffb1dc2SBharat Bhushan MPC8544_UTIL_OFFSET); 4715a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, gutil); 4725a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, gutil, "compatible", "fsl,mpc8544-guts"); 4735a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, gutil, "reg", MPC8544_UTIL_OFFSET, 0x1000); 4745a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, gutil, "fsl,has-rstcr", NULL, 0); 475f5038483SAlexander Graf 476a911b7a9SAlexander Graf snprintf(msi, sizeof(msi), "/%s/msi@%llx", soc, MPC8544_MSI_REGS_OFFSET); 4775a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, msi); 4785a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, msi, "compatible", "fsl,mpic-msi"); 4795a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, msi, "reg", MPC8544_MSI_REGS_OFFSET, 0x200); 4805a4348d1SPeter Crosthwaite msi_ph = qemu_fdt_alloc_phandle(fdt); 4815a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, msi, "msi-available-ranges", 0x0, 0x100); 4825a4348d1SPeter Crosthwaite qemu_fdt_setprop_phandle(fdt, msi, "interrupt-parent", mpic); 4835a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, msi, "interrupts", 484a911b7a9SAlexander Graf 0xe0, 0x0, 485a911b7a9SAlexander Graf 0xe1, 0x0, 486a911b7a9SAlexander Graf 0xe2, 0x0, 487a911b7a9SAlexander Graf 0xe3, 0x0, 488a911b7a9SAlexander Graf 0xe4, 0x0, 489a911b7a9SAlexander Graf 0xe5, 0x0, 490a911b7a9SAlexander Graf 0xe6, 0x0, 491a911b7a9SAlexander Graf 0xe7, 0x0); 4925a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, msi, "phandle", msi_ph); 4935a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, msi, "linux,phandle", msi_ph); 494a911b7a9SAlexander Graf 4952eaaac1fSAlexander Graf snprintf(pci, sizeof(pci), "/pci@%llx", 4962eaaac1fSAlexander Graf params->ccsrbar_base + MPC8544_PCI_REGS_OFFSET); 4975a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, pci); 4985a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, pci, "cell-index", 0); 4995a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, pci, "compatible", "fsl,mpc8540-pci"); 5005a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, pci, "device_type", "pci"); 5015a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, pci, "interrupt-map-mask", 0xf800, 0x0, 5020dbc0798SAlexander Graf 0x0, 0x7); 5035a4348d1SPeter Crosthwaite pci_map = pci_map_create(fdt, qemu_fdt_get_phandle(fdt, mpic), 504492ec48dSAlexander Graf params->pci_first_slot, params->pci_nr_slots, 505492ec48dSAlexander Graf &len); 5065a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, pci, "interrupt-map", pci_map, len); 5075a4348d1SPeter Crosthwaite qemu_fdt_setprop_phandle(fdt, pci, "interrupt-parent", mpic); 5085a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, pci, "interrupts", 24, 2); 5095a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, pci, "bus-range", 0, 255); 5103627757eSAlexander Graf for (i = 0; i < 14; i++) { 5110dbc0798SAlexander Graf pci_ranges[i] = cpu_to_be32(pci_ranges[i]); 5120dbc0798SAlexander Graf } 5135a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, pci, "fsl,msi", msi_ph); 5145a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, pci, "ranges", pci_ranges, sizeof(pci_ranges)); 5152eaaac1fSAlexander Graf qemu_fdt_setprop_cells(fdt, pci, "reg", 5162eaaac1fSAlexander Graf (params->ccsrbar_base + MPC8544_PCI_REGS_OFFSET) >> 32, 5172eaaac1fSAlexander Graf (params->ccsrbar_base + MPC8544_PCI_REGS_OFFSET), 5182eaaac1fSAlexander Graf 0, 0x1000); 5195a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, pci, "clock-frequency", 66666666); 5205a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, pci, "#interrupt-cells", 1); 5215a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, pci, "#size-cells", 2); 5225a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, pci, "#address-cells", 3); 5235a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, "/aliases", "pci0", pci); 5240dbc0798SAlexander Graf 525b88e77f4SAlexander Graf if (params->has_mpc8xxx_gpio) { 526b88e77f4SAlexander Graf create_dt_mpc8xxx_gpio(fdt, soc, mpic); 527b88e77f4SAlexander Graf } 528b88e77f4SAlexander Graf 529f7087343SAlexander Graf if (params->has_platform_bus) { 530f7087343SAlexander Graf platform_bus_create_devtree(params, fdt, mpic); 531f7087343SAlexander Graf } 532f7087343SAlexander Graf 533e6eaabebSScott Wood params->fixup_devtree(params, fdt); 534e6eaabebSScott Wood 535e6eaabebSScott Wood if (toplevel_compat) { 5365a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, "/", "compatible", toplevel_compat, 537e6eaabebSScott Wood strlen(toplevel_compat) + 1); 538e6eaabebSScott Wood } 539e6eaabebSScott Wood 540d1b93565SAlexander Graf done: 54128290f37SAlexander Graf if (!dry_run) { 5425a4348d1SPeter Crosthwaite qemu_fdt_dumpdtb(fdt, fdt_size); 54328290f37SAlexander Graf cpu_physical_memory_write(addr, fdt, fdt_size); 544cba2026aSAlexander Graf } 545cba2026aSAlexander Graf ret = fdt_size; 5467ec632b4Spbrook 5471db09b84Saurel32 out: 548347dd79dSAlexander Graf g_free(pci_map); 5491db09b84Saurel32 55004088adbSLiu Yu return ret; 5511db09b84Saurel32 } 5521db09b84Saurel32 55328290f37SAlexander Graf typedef struct DeviceTreeParams { 5543ef96221SMarcel Apfelbaum MachineState *machine; 55528290f37SAlexander Graf PPCE500Params params; 55628290f37SAlexander Graf hwaddr addr; 55728290f37SAlexander Graf hwaddr initrd_base; 55828290f37SAlexander Graf hwaddr initrd_size; 559903585deSAlexander Graf hwaddr kernel_base; 560903585deSAlexander Graf hwaddr kernel_size; 561f7087343SAlexander Graf Notifier notifier; 56228290f37SAlexander Graf } DeviceTreeParams; 56328290f37SAlexander Graf 56428290f37SAlexander Graf static void ppce500_reset_device_tree(void *opaque) 56528290f37SAlexander Graf { 56628290f37SAlexander Graf DeviceTreeParams *p = opaque; 5673812c71fSAlexander Graf ppce500_load_device_tree(p->machine, &p->params, p->addr, p->initrd_base, 568903585deSAlexander Graf p->initrd_size, p->kernel_base, p->kernel_size, 569903585deSAlexander Graf false); 57028290f37SAlexander Graf } 57128290f37SAlexander Graf 572f7087343SAlexander Graf static void ppce500_init_notify(Notifier *notifier, void *data) 573f7087343SAlexander Graf { 574f7087343SAlexander Graf DeviceTreeParams *p = container_of(notifier, DeviceTreeParams, notifier); 575f7087343SAlexander Graf ppce500_reset_device_tree(p); 576f7087343SAlexander Graf } 577f7087343SAlexander Graf 5783ef96221SMarcel Apfelbaum static int ppce500_prep_device_tree(MachineState *machine, 57928290f37SAlexander Graf PPCE500Params *params, 58028290f37SAlexander Graf hwaddr addr, 58128290f37SAlexander Graf hwaddr initrd_base, 582903585deSAlexander Graf hwaddr initrd_size, 583903585deSAlexander Graf hwaddr kernel_base, 584903585deSAlexander Graf hwaddr kernel_size) 58528290f37SAlexander Graf { 58628290f37SAlexander Graf DeviceTreeParams *p = g_new(DeviceTreeParams, 1); 5873ef96221SMarcel Apfelbaum p->machine = machine; 58828290f37SAlexander Graf p->params = *params; 58928290f37SAlexander Graf p->addr = addr; 59028290f37SAlexander Graf p->initrd_base = initrd_base; 59128290f37SAlexander Graf p->initrd_size = initrd_size; 592903585deSAlexander Graf p->kernel_base = kernel_base; 593903585deSAlexander Graf p->kernel_size = kernel_size; 59428290f37SAlexander Graf 59528290f37SAlexander Graf qemu_register_reset(ppce500_reset_device_tree, p); 596f7087343SAlexander Graf p->notifier.notify = ppce500_init_notify; 597f7087343SAlexander Graf qemu_add_machine_init_done_notifier(&p->notifier); 59828290f37SAlexander Graf 59928290f37SAlexander Graf /* Issue the device tree loader once, so that we get the size of the blob */ 6003ef96221SMarcel Apfelbaum return ppce500_load_device_tree(machine, params, addr, initrd_base, 601903585deSAlexander Graf initrd_size, kernel_base, kernel_size, 602903585deSAlexander Graf true); 60328290f37SAlexander Graf } 60428290f37SAlexander Graf 605cba2026aSAlexander Graf /* Create -kernel TLB entries for BookE. */ 606a36848ffSAaron Larson hwaddr booke206_page_size_to_tlb(uint64_t size) 607d1e256feSAlexander Graf { 608cba2026aSAlexander Graf return 63 - clz64(size >> 10); 609d1e256feSAlexander Graf } 610d1e256feSAlexander Graf 611cefd3cdbSBharat Bhushan static int booke206_initial_map_tsize(CPUPPCState *env) 6123b989d49SAlexander Graf { 613cba2026aSAlexander Graf struct boot_info *bi = env->load_info; 614cefd3cdbSBharat Bhushan hwaddr dt_end; 615cba2026aSAlexander Graf int ps; 6163b989d49SAlexander Graf 617cba2026aSAlexander Graf /* Our initial TLB entry needs to cover everything from 0 to 618cba2026aSAlexander Graf the device tree top */ 619cba2026aSAlexander Graf dt_end = bi->dt_base + bi->dt_size; 620cba2026aSAlexander Graf ps = booke206_page_size_to_tlb(dt_end) + 1; 621fb37c302SAlexander Graf if (ps & 1) { 622fb37c302SAlexander Graf /* e500v2 can only do even TLB size bits */ 623fb37c302SAlexander Graf ps++; 624fb37c302SAlexander Graf } 625cefd3cdbSBharat Bhushan return ps; 626cefd3cdbSBharat Bhushan } 627cefd3cdbSBharat Bhushan 628cefd3cdbSBharat Bhushan static uint64_t mmubooke_initial_mapsize(CPUPPCState *env) 629cefd3cdbSBharat Bhushan { 630cefd3cdbSBharat Bhushan int tsize; 631cefd3cdbSBharat Bhushan 632cefd3cdbSBharat Bhushan tsize = booke206_initial_map_tsize(env); 633cefd3cdbSBharat Bhushan return (1ULL << 10 << tsize); 634cefd3cdbSBharat Bhushan } 635cefd3cdbSBharat Bhushan 636cefd3cdbSBharat Bhushan static void mmubooke_create_initial_mapping(CPUPPCState *env) 637cefd3cdbSBharat Bhushan { 638cefd3cdbSBharat Bhushan ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0); 639cefd3cdbSBharat Bhushan hwaddr size; 640cefd3cdbSBharat Bhushan int ps; 641cefd3cdbSBharat Bhushan 642cefd3cdbSBharat Bhushan ps = booke206_initial_map_tsize(env); 643cba2026aSAlexander Graf size = (ps << MAS1_TSIZE_SHIFT); 644d1e256feSAlexander Graf tlb->mas1 = MAS1_VALID | size; 645cba2026aSAlexander Graf tlb->mas2 = 0; 646cba2026aSAlexander Graf tlb->mas7_3 = 0; 647d1e256feSAlexander Graf tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX; 64893dd5e85SScott Wood 64993dd5e85SScott Wood env->tlb_dirty = true; 6503b989d49SAlexander Graf } 6513b989d49SAlexander Graf 652b3305981SScott Wood static void ppce500_cpu_reset_sec(void *opaque) 6535c145dacSAlexander Graf { 65438f92da6SAndreas Färber PowerPCCPU *cpu = opaque; 655259186a7SAndreas Färber CPUState *cs = CPU(cpu); 6565c145dacSAlexander Graf 657259186a7SAndreas Färber cpu_reset(cs); 6585c145dacSAlexander Graf 6595c145dacSAlexander Graf /* Secondary CPU starts in halted state for now. Needs to change when 6605c145dacSAlexander Graf implementing non-kernel boot. */ 661259186a7SAndreas Färber cs->halted = 1; 66227103424SAndreas Färber cs->exception_index = EXCP_HLT; 6633b989d49SAlexander Graf } 6643b989d49SAlexander Graf 665b3305981SScott Wood static void ppce500_cpu_reset(void *opaque) 6663b989d49SAlexander Graf { 66738f92da6SAndreas Färber PowerPCCPU *cpu = opaque; 668259186a7SAndreas Färber CPUState *cs = CPU(cpu); 66938f92da6SAndreas Färber CPUPPCState *env = &cpu->env; 6703b989d49SAlexander Graf struct boot_info *bi = env->load_info; 6713b989d49SAlexander Graf 672259186a7SAndreas Färber cpu_reset(cs); 6733b989d49SAlexander Graf 6743b989d49SAlexander Graf /* Set initial guest state. */ 675259186a7SAndreas Färber cs->halted = 0; 6763b989d49SAlexander Graf env->gpr[1] = (16<<20) - 8; 6773b989d49SAlexander Graf env->gpr[3] = bi->dt_base; 678cefd3cdbSBharat Bhushan env->gpr[4] = 0; 679cefd3cdbSBharat Bhushan env->gpr[5] = 0; 680cefd3cdbSBharat Bhushan env->gpr[6] = EPAPR_MAGIC; 681cefd3cdbSBharat Bhushan env->gpr[7] = mmubooke_initial_mapsize(env); 682cefd3cdbSBharat Bhushan env->gpr[8] = 0; 683cefd3cdbSBharat Bhushan env->gpr[9] = 0; 6843b989d49SAlexander Graf env->nip = bi->entry; 685cba2026aSAlexander Graf mmubooke_create_initial_mapping(env); 6863b989d49SAlexander Graf } 6873b989d49SAlexander Graf 688d85937e6SScott Wood static DeviceState *ppce500_init_mpic_qemu(PPCE500Params *params, 68982fc73b6SScott Wood qemu_irq **irqs) 69082fc73b6SScott Wood { 69182fc73b6SScott Wood DeviceState *dev; 69282fc73b6SScott Wood SysBusDevice *s; 69382fc73b6SScott Wood int i, j, k; 69482fc73b6SScott Wood 695e1766344SAndreas Färber dev = qdev_create(NULL, TYPE_OPENPIC); 696e75ce32aSMichael Davidsaver object_property_add_child(qdev_get_machine(), "pic", OBJECT(dev), 697e75ce32aSMichael Davidsaver &error_fatal); 69882fc73b6SScott Wood qdev_prop_set_uint32(dev, "model", params->mpic_version); 699d85937e6SScott Wood qdev_prop_set_uint32(dev, "nb_cpus", smp_cpus); 700d85937e6SScott Wood 70182fc73b6SScott Wood qdev_init_nofail(dev); 70282fc73b6SScott Wood s = SYS_BUS_DEVICE(dev); 70382fc73b6SScott Wood 70482fc73b6SScott Wood k = 0; 70582fc73b6SScott Wood for (i = 0; i < smp_cpus; i++) { 70682fc73b6SScott Wood for (j = 0; j < OPENPIC_OUTPUT_NB; j++) { 70782fc73b6SScott Wood sysbus_connect_irq(s, k++, irqs[i][j]); 70882fc73b6SScott Wood } 70982fc73b6SScott Wood } 71082fc73b6SScott Wood 711d85937e6SScott Wood return dev; 712d85937e6SScott Wood } 713d85937e6SScott Wood 714d85937e6SScott Wood static DeviceState *ppce500_init_mpic_kvm(PPCE500Params *params, 715fe656ebdSMarkus Armbruster qemu_irq **irqs, Error **errp) 716d85937e6SScott Wood { 717fe656ebdSMarkus Armbruster Error *err = NULL; 718d85937e6SScott Wood DeviceState *dev; 719d85937e6SScott Wood CPUState *cs; 720d85937e6SScott Wood 721dd49c038SAndreas Färber dev = qdev_create(NULL, TYPE_KVM_OPENPIC); 722d85937e6SScott Wood qdev_prop_set_uint32(dev, "model", params->mpic_version); 723d85937e6SScott Wood 724fe656ebdSMarkus Armbruster object_property_set_bool(OBJECT(dev), true, "realized", &err); 725fe656ebdSMarkus Armbruster if (err) { 726fe656ebdSMarkus Armbruster error_propagate(errp, err); 727fe656ebdSMarkus Armbruster object_unparent(OBJECT(dev)); 728d85937e6SScott Wood return NULL; 729d85937e6SScott Wood } 730d85937e6SScott Wood 731bdc44640SAndreas Färber CPU_FOREACH(cs) { 732d85937e6SScott Wood if (kvm_openpic_connect_vcpu(dev, cs)) { 733d85937e6SScott Wood fprintf(stderr, "%s: failed to connect vcpu to irqchip\n", 734d85937e6SScott Wood __func__); 735d85937e6SScott Wood abort(); 736d85937e6SScott Wood } 737d85937e6SScott Wood } 738d85937e6SScott Wood 739d85937e6SScott Wood return dev; 740d85937e6SScott Wood } 741d85937e6SScott Wood 742c91c187fSMichael Davidsaver static DeviceState *ppce500_init_mpic(MachineState *machine, 743c91c187fSMichael Davidsaver PPCE500Params *params, 744c91c187fSMichael Davidsaver MemoryRegion *ccsr, 745c91c187fSMichael Davidsaver qemu_irq **irqs) 746d85937e6SScott Wood { 747d85937e6SScott Wood DeviceState *dev = NULL; 748d85937e6SScott Wood SysBusDevice *s; 749d85937e6SScott Wood 750d85937e6SScott Wood if (kvm_enabled()) { 751fe656ebdSMarkus Armbruster Error *err = NULL; 752d85937e6SScott Wood 753446f16a6SMarcel Apfelbaum if (machine_kernel_irqchip_allowed(machine)) { 754fe656ebdSMarkus Armbruster dev = ppce500_init_mpic_kvm(params, irqs, &err); 755d85937e6SScott Wood } 756446f16a6SMarcel Apfelbaum if (machine_kernel_irqchip_required(machine) && !dev) { 757c29b77f9SMarkus Armbruster error_reportf_err(err, 758c29b77f9SMarkus Armbruster "kernel_irqchip requested but unavailable: "); 759fe656ebdSMarkus Armbruster exit(1); 760d85937e6SScott Wood } 761d85937e6SScott Wood } 762d85937e6SScott Wood 763d85937e6SScott Wood if (!dev) { 764d85937e6SScott Wood dev = ppce500_init_mpic_qemu(params, irqs); 765d85937e6SScott Wood } 766d85937e6SScott Wood 767d85937e6SScott Wood s = SYS_BUS_DEVICE(dev); 76882fc73b6SScott Wood memory_region_add_subregion(ccsr, MPC8544_MPIC_REGS_OFFSET, 76982fc73b6SScott Wood s->mmio[0].memory); 77082fc73b6SScott Wood 771c91c187fSMichael Davidsaver return dev; 77282fc73b6SScott Wood } 77382fc73b6SScott Wood 774016f7758SAlexander Graf static void ppce500_power_off(void *opaque, int line, int on) 775016f7758SAlexander Graf { 776016f7758SAlexander Graf if (on) { 777cf83f140SEric Blake qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); 778016f7758SAlexander Graf } 779016f7758SAlexander Graf } 780016f7758SAlexander Graf 7813ef96221SMarcel Apfelbaum void ppce500_init(MachineState *machine, PPCE500Params *params) 7821db09b84Saurel32 { 78339186d8aSRichard Henderson MemoryRegion *address_space_mem = get_system_memory(); 7842646c133SAvi Kivity MemoryRegion *ram = g_new(MemoryRegion, 1); 7851db09b84Saurel32 PCIBus *pci_bus; 786e2684c0bSAndreas Färber CPUPPCState *env = NULL; 7873812c71fSAlexander Graf uint64_t loadaddr; 7883812c71fSAlexander Graf hwaddr kernel_base = -1LL; 7893812c71fSAlexander Graf int kernel_size = 0; 7903812c71fSAlexander Graf hwaddr dt_base = 0; 7913812c71fSAlexander Graf hwaddr initrd_base = 0; 7923812c71fSAlexander Graf int initrd_size = 0; 7933812c71fSAlexander Graf hwaddr cur_base = 0; 7943812c71fSAlexander Graf char *filename; 7953812c71fSAlexander Graf hwaddr bios_entry = 0; 7963812c71fSAlexander Graf target_long bios_size; 7973812c71fSAlexander Graf struct boot_info *boot_info; 7983812c71fSAlexander Graf int dt_size; 79982fc73b6SScott Wood int i; 800d575a6ceSBharat Bhushan /* irq num for pin INTA, INTB, INTC and INTD is 1, 2, 3 and 801d575a6ceSBharat Bhushan * 4 respectively */ 802d575a6ceSBharat Bhushan unsigned int pci_irq_nrs[PCI_NUM_PINS] = {1, 2, 3, 4}; 803c91c187fSMichael Davidsaver qemu_irq **irqs; 804c91c187fSMichael Davidsaver DeviceState *dev, *mpicdev; 805e2684c0bSAndreas Färber CPUPPCState *firstenv = NULL; 8063eddc1beSBharat Bhushan MemoryRegion *ccsr_addr_space; 807dffb1dc2SBharat Bhushan SysBusDevice *s; 8083eddc1beSBharat Bhushan PPCE500CCSRState *ccsr; 8091db09b84Saurel32 810a915249fSAlexander Graf irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *)); 811a915249fSAlexander Graf irqs[0] = g_malloc0(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB); 812e61c36d5SAlexander Graf for (i = 0; i < smp_cpus; i++) { 813397b457dSAndreas Färber PowerPCCPU *cpu; 81455e5c285SAndreas Färber CPUState *cs; 815e61c36d5SAlexander Graf qemu_irq *input; 816397b457dSAndreas Färber 81759e816fdSIgor Mammedov cpu = POWERPC_CPU(cpu_create(machine->cpu_type)); 818397b457dSAndreas Färber env = &cpu->env; 81955e5c285SAndreas Färber cs = CPU(cpu); 8201db09b84Saurel32 82100469dc3SValentin Plotkin if (env->mmu_model != POWERPC_MMU_BOOKE206) { 8226f76b817SAlistair Francis error_report("MMU model %i not supported by this machine", 82300469dc3SValentin Plotkin env->mmu_model); 82400469dc3SValentin Plotkin exit(1); 82500469dc3SValentin Plotkin } 82600469dc3SValentin Plotkin 827e61c36d5SAlexander Graf if (!firstenv) { 828e61c36d5SAlexander Graf firstenv = env; 829e61c36d5SAlexander Graf } 830e61c36d5SAlexander Graf 831a915249fSAlexander Graf irqs[i] = irqs[0] + (i * OPENPIC_OUTPUT_NB); 832a915249fSAlexander Graf input = (qemu_irq *)env->irq_inputs; 833a915249fSAlexander Graf irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT]; 834a915249fSAlexander Graf irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT]; 8356a450df9SAlexander Graf env->spr_cb[SPR_BOOKE_PIR].default_value = cs->cpu_index = i; 8362eaaac1fSAlexander Graf env->mpic_iack = params->ccsrbar_base + 837bd25922eSScott Wood MPC8544_MPIC_REGS_OFFSET + 0xa0; 838e61c36d5SAlexander Graf 839a34a92b9SAndreas Färber ppc_booke_timers_init(cpu, 400000000, PPC_TIMER_E500); 8403b989d49SAlexander Graf 8413b989d49SAlexander Graf /* Register reset handler */ 8425c145dacSAlexander Graf if (!i) { 8435c145dacSAlexander Graf /* Primary CPU */ 8445c145dacSAlexander Graf struct boot_info *boot_info; 845e61c36d5SAlexander Graf boot_info = g_malloc0(sizeof(struct boot_info)); 846b3305981SScott Wood qemu_register_reset(ppce500_cpu_reset, cpu); 847e61c36d5SAlexander Graf env->load_info = boot_info; 8485c145dacSAlexander Graf } else { 8495c145dacSAlexander Graf /* Secondary CPUs */ 850b3305981SScott Wood qemu_register_reset(ppce500_cpu_reset_sec, cpu); 8515c145dacSAlexander Graf } 852e61c36d5SAlexander Graf } 853e61c36d5SAlexander Graf 854e61c36d5SAlexander Graf env = firstenv; 8553b989d49SAlexander Graf 8561db09b84Saurel32 /* Fixup Memory size on a alignment boundary */ 8571db09b84Saurel32 ram_size &= ~(RAM_SIZES_ALIGN - 1); 8583ef96221SMarcel Apfelbaum machine->ram_size = ram_size; 8591db09b84Saurel32 8601db09b84Saurel32 /* Register Memory */ 861e938ba0cSShreyas B. Prabhu memory_region_allocate_system_memory(ram, NULL, "mpc8544ds.ram", ram_size); 8622646c133SAvi Kivity memory_region_add_subregion(address_space_mem, 0, ram); 8631db09b84Saurel32 8643eddc1beSBharat Bhushan dev = qdev_create(NULL, "e500-ccsr"); 8653eddc1beSBharat Bhushan object_property_add_child(qdev_get_machine(), "e500-ccsr", 8663eddc1beSBharat Bhushan OBJECT(dev), NULL); 8673eddc1beSBharat Bhushan qdev_init_nofail(dev); 8683eddc1beSBharat Bhushan ccsr = CCSR(dev); 8693eddc1beSBharat Bhushan ccsr_addr_space = &ccsr->ccsr_space; 8702eaaac1fSAlexander Graf memory_region_add_subregion(address_space_mem, params->ccsrbar_base, 8713eddc1beSBharat Bhushan ccsr_addr_space); 872dffb1dc2SBharat Bhushan 873c91c187fSMichael Davidsaver mpicdev = ppce500_init_mpic(machine, params, ccsr_addr_space, irqs); 8741db09b84Saurel32 8751db09b84Saurel32 /* Serial */ 8762d48377aSBlue Swirl if (serial_hds[0]) { 8773eddc1beSBharat Bhushan serial_mm_init(ccsr_addr_space, MPC8544_SERIAL0_REGS_OFFSET, 878c91c187fSMichael Davidsaver 0, qdev_get_gpio_in(mpicdev, 42), 399193, 8792ff0c7c3SRichard Henderson serial_hds[0], DEVICE_BIG_ENDIAN); 8802d48377aSBlue Swirl } 8811db09b84Saurel32 8822d48377aSBlue Swirl if (serial_hds[1]) { 8833eddc1beSBharat Bhushan serial_mm_init(ccsr_addr_space, MPC8544_SERIAL1_REGS_OFFSET, 884c91c187fSMichael Davidsaver 0, qdev_get_gpio_in(mpicdev, 42), 399193, 88559de4f98SBharat Bhushan serial_hds[1], DEVICE_BIG_ENDIAN); 8862d48377aSBlue Swirl } 8871db09b84Saurel32 888b0fb8423SAlexander Graf /* General Utility device */ 889dffb1dc2SBharat Bhushan dev = qdev_create(NULL, "mpc8544-guts"); 890dffb1dc2SBharat Bhushan qdev_init_nofail(dev); 891dffb1dc2SBharat Bhushan s = SYS_BUS_DEVICE(dev); 8923eddc1beSBharat Bhushan memory_region_add_subregion(ccsr_addr_space, MPC8544_UTIL_OFFSET, 893dffb1dc2SBharat Bhushan sysbus_mmio_get_region(s, 0)); 894b0fb8423SAlexander Graf 8951db09b84Saurel32 /* PCI */ 896dffb1dc2SBharat Bhushan dev = qdev_create(NULL, "e500-pcihost"); 897e75ce32aSMichael Davidsaver object_property_add_child(qdev_get_machine(), "pci-host", OBJECT(dev), 898e75ce32aSMichael Davidsaver &error_abort); 899492ec48dSAlexander Graf qdev_prop_set_uint32(dev, "first_slot", params->pci_first_slot); 9003016dca0SBharat Bhushan qdev_prop_set_uint32(dev, "first_pin_irq", pci_irq_nrs[0]); 901dffb1dc2SBharat Bhushan qdev_init_nofail(dev); 902dffb1dc2SBharat Bhushan s = SYS_BUS_DEVICE(dev); 903d575a6ceSBharat Bhushan for (i = 0; i < PCI_NUM_PINS; i++) { 904c91c187fSMichael Davidsaver sysbus_connect_irq(s, i, qdev_get_gpio_in(mpicdev, pci_irq_nrs[i])); 905d575a6ceSBharat Bhushan } 906d575a6ceSBharat Bhushan 9073eddc1beSBharat Bhushan memory_region_add_subregion(ccsr_addr_space, MPC8544_PCI_REGS_OFFSET, 908dffb1dc2SBharat Bhushan sysbus_mmio_get_region(s, 0)); 909dffb1dc2SBharat Bhushan 910d461e3b9SAlexander Graf pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0"); 9111db09b84Saurel32 if (!pci_bus) 9121db09b84Saurel32 printf("couldn't create PCI controller!\n"); 9131db09b84Saurel32 9141db09b84Saurel32 if (pci_bus) { 9151db09b84Saurel32 /* Register network interfaces. */ 9161db09b84Saurel32 for (i = 0; i < nb_nics; i++) { 91729b358f9SDavid Gibson pci_nic_init_nofail(&nd_table[i], pci_bus, "virtio", NULL); 9181db09b84Saurel32 } 9191db09b84Saurel32 } 9201db09b84Saurel32 9215c145dacSAlexander Graf /* Register spinning region */ 9222eaaac1fSAlexander Graf sysbus_create_simple("e500-spin", params->spin_base, NULL); 9235c145dacSAlexander Graf 9243812c71fSAlexander Graf if (cur_base < (32 * 1024 * 1024)) { 9253812c71fSAlexander Graf /* u-boot occupies memory up to 32MB, so load blobs above */ 9263812c71fSAlexander Graf cur_base = (32 * 1024 * 1024); 9273812c71fSAlexander Graf } 9283812c71fSAlexander Graf 929b88e77f4SAlexander Graf if (params->has_mpc8xxx_gpio) { 930016f7758SAlexander Graf qemu_irq poweroff_irq; 931016f7758SAlexander Graf 932b88e77f4SAlexander Graf dev = qdev_create(NULL, "mpc8xxx_gpio"); 933b88e77f4SAlexander Graf s = SYS_BUS_DEVICE(dev); 934b88e77f4SAlexander Graf qdev_init_nofail(dev); 935c91c187fSMichael Davidsaver sysbus_connect_irq(s, 0, qdev_get_gpio_in(mpicdev, MPC8XXX_GPIO_IRQ)); 936b88e77f4SAlexander Graf memory_region_add_subregion(ccsr_addr_space, MPC8XXX_GPIO_OFFSET, 937b88e77f4SAlexander Graf sysbus_mmio_get_region(s, 0)); 938016f7758SAlexander Graf 939016f7758SAlexander Graf /* Power Off GPIO at Pin 0 */ 940016f7758SAlexander Graf poweroff_irq = qemu_allocate_irq(ppce500_power_off, NULL, 0); 941016f7758SAlexander Graf qdev_connect_gpio_out(dev, 0, poweroff_irq); 942b88e77f4SAlexander Graf } 943b88e77f4SAlexander Graf 944f7087343SAlexander Graf /* Platform Bus Device */ 945f7087343SAlexander Graf if (params->has_platform_bus) { 946f7087343SAlexander Graf dev = qdev_create(NULL, TYPE_PLATFORM_BUS_DEVICE); 947f7087343SAlexander Graf dev->id = TYPE_PLATFORM_BUS_DEVICE; 948f7087343SAlexander Graf qdev_prop_set_uint32(dev, "num_irqs", params->platform_bus_num_irqs); 949f7087343SAlexander Graf qdev_prop_set_uint32(dev, "mmio_size", params->platform_bus_size); 950f7087343SAlexander Graf qdev_init_nofail(dev); 951f7087343SAlexander Graf s = SYS_BUS_DEVICE(dev); 952f7087343SAlexander Graf 953f7087343SAlexander Graf for (i = 0; i < params->platform_bus_num_irqs; i++) { 954f7087343SAlexander Graf int irqn = params->platform_bus_first_irq + i; 955c91c187fSMichael Davidsaver sysbus_connect_irq(s, i, qdev_get_gpio_in(mpicdev, irqn)); 956f7087343SAlexander Graf } 957f7087343SAlexander Graf 958f7087343SAlexander Graf memory_region_add_subregion(address_space_mem, 959f7087343SAlexander Graf params->platform_bus_base, 960f7087343SAlexander Graf sysbus_mmio_get_region(s, 0)); 961f7087343SAlexander Graf } 962f7087343SAlexander Graf 9631db09b84Saurel32 /* Load kernel. */ 9643ef96221SMarcel Apfelbaum if (machine->kernel_filename) { 9653812c71fSAlexander Graf kernel_base = cur_base; 9663812c71fSAlexander Graf kernel_size = load_image_targphys(machine->kernel_filename, 9673812c71fSAlexander Graf cur_base, 9683812c71fSAlexander Graf ram_size - cur_base); 9691db09b84Saurel32 if (kernel_size < 0) { 9706f76b817SAlistair Francis error_report("could not load kernel '%s'", 9713ef96221SMarcel Apfelbaum machine->kernel_filename); 9721db09b84Saurel32 exit(1); 9731db09b84Saurel32 } 974528e536eSAlexander Graf 9753812c71fSAlexander Graf cur_base += kernel_size; 9761db09b84Saurel32 } 9771db09b84Saurel32 9781db09b84Saurel32 /* Load initrd. */ 9793ef96221SMarcel Apfelbaum if (machine->initrd_filename) { 980528e536eSAlexander Graf initrd_base = (cur_base + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK; 9813ef96221SMarcel Apfelbaum initrd_size = load_image_targphys(machine->initrd_filename, initrd_base, 982d7585251Spbrook ram_size - initrd_base); 9831db09b84Saurel32 9841db09b84Saurel32 if (initrd_size < 0) { 9856f76b817SAlistair Francis error_report("could not load initial ram disk '%s'", 9863ef96221SMarcel Apfelbaum machine->initrd_filename); 9871db09b84Saurel32 exit(1); 9881db09b84Saurel32 } 989528e536eSAlexander Graf 990528e536eSAlexander Graf cur_base = initrd_base + initrd_size; 9911db09b84Saurel32 } 9921db09b84Saurel32 9933812c71fSAlexander Graf /* 9943812c71fSAlexander Graf * Smart firmware defaults ahead! 9953812c71fSAlexander Graf * 9963812c71fSAlexander Graf * We follow the following table to select which payload we execute. 9973812c71fSAlexander Graf * 9983812c71fSAlexander Graf * -kernel | -bios | payload 9993812c71fSAlexander Graf * ---------+-------+--------- 10003812c71fSAlexander Graf * N | Y | u-boot 10013812c71fSAlexander Graf * N | N | u-boot 10023812c71fSAlexander Graf * Y | Y | u-boot 10033812c71fSAlexander Graf * Y | N | kernel 10043812c71fSAlexander Graf * 10053812c71fSAlexander Graf * This ensures backwards compatibility with how we used to expose 10063812c71fSAlexander Graf * -kernel to users but allows them to run through u-boot as well. 10073812c71fSAlexander Graf */ 10083812c71fSAlexander Graf if (bios_name == NULL) { 10093ef96221SMarcel Apfelbaum if (machine->kernel_filename) { 10103812c71fSAlexander Graf bios_name = machine->kernel_filename; 10113812c71fSAlexander Graf } else { 10123812c71fSAlexander Graf bios_name = "u-boot.e500"; 10133812c71fSAlexander Graf } 10143812c71fSAlexander Graf } 10153812c71fSAlexander Graf filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); 10163812c71fSAlexander Graf 10173812c71fSAlexander Graf bios_size = load_elf(filename, NULL, NULL, &bios_entry, &loadaddr, NULL, 10187ef295eaSPeter Crosthwaite 1, PPC_ELF_MACHINE, 0, 0); 10193812c71fSAlexander Graf if (bios_size < 0) { 10203812c71fSAlexander Graf /* 10213812c71fSAlexander Graf * Hrm. No ELF image? Try a uImage, maybe someone is giving us an 10223812c71fSAlexander Graf * ePAPR compliant kernel 10233812c71fSAlexander Graf */ 102425bda50aSMax Filippov kernel_size = load_uimage(filename, &bios_entry, &loadaddr, NULL, 102525bda50aSMax Filippov NULL, NULL); 10263812c71fSAlexander Graf if (kernel_size < 0) { 10276f76b817SAlistair Francis error_report("could not load firmware '%s'", filename); 10283812c71fSAlexander Graf exit(1); 10293812c71fSAlexander Graf } 10303812c71fSAlexander Graf } 1031f19377bfSShannon Zhao g_free(filename); 10323812c71fSAlexander Graf 10333812c71fSAlexander Graf /* Reserve space for dtb */ 10343812c71fSAlexander Graf dt_base = (loadaddr + bios_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK; 10355c145dacSAlexander Graf 10363ef96221SMarcel Apfelbaum dt_size = ppce500_prep_device_tree(machine, params, dt_base, 1037903585deSAlexander Graf initrd_base, initrd_size, 10383812c71fSAlexander Graf kernel_base, kernel_size); 1039cba2026aSAlexander Graf if (dt_size < 0) { 10406f76b817SAlistair Francis error_report("couldn't load device tree"); 10411db09b84Saurel32 exit(1); 10421db09b84Saurel32 } 1043b8dec144SAlexander Graf assert(dt_size < DTB_MAX_SIZE); 10441db09b84Saurel32 1045e61c36d5SAlexander Graf boot_info = env->load_info; 10463812c71fSAlexander Graf boot_info->entry = bios_entry; 10473b989d49SAlexander Graf boot_info->dt_base = dt_base; 1048cba2026aSAlexander Graf boot_info->dt_size = dt_size; 10491db09b84Saurel32 } 10503eddc1beSBharat Bhushan 1051d0c2b0d0Sxiaoqiang zhao static void e500_ccsr_initfn(Object *obj) 10523eddc1beSBharat Bhushan { 1053d0c2b0d0Sxiaoqiang zhao PPCE500CCSRState *ccsr = CCSR(obj); 1054d0c2b0d0Sxiaoqiang zhao memory_region_init(&ccsr->ccsr_space, obj, "e500-ccsr", 10553eddc1beSBharat Bhushan MPC8544_CCSRBAR_SIZE); 10563eddc1beSBharat Bhushan } 10573eddc1beSBharat Bhushan 10583eddc1beSBharat Bhushan static const TypeInfo e500_ccsr_info = { 10593eddc1beSBharat Bhushan .name = TYPE_CCSR, 10603eddc1beSBharat Bhushan .parent = TYPE_SYS_BUS_DEVICE, 10613eddc1beSBharat Bhushan .instance_size = sizeof(PPCE500CCSRState), 1062d0c2b0d0Sxiaoqiang zhao .instance_init = e500_ccsr_initfn, 10633eddc1beSBharat Bhushan }; 10643eddc1beSBharat Bhushan 10653eddc1beSBharat Bhushan static void e500_register_types(void) 10663eddc1beSBharat Bhushan { 10673eddc1beSBharat Bhushan type_register_static(&e500_ccsr_info); 10683eddc1beSBharat Bhushan } 10693eddc1beSBharat Bhushan 10703eddc1beSBharat Bhushan type_init(e500_register_types) 1071