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" 18*a8d25326SMarkus Armbruster #include "qemu-common.h" 19ab3dd749SPhilippe Mathieu-Daudé #include "qemu/units.h" 20da34e65cSMarkus Armbruster #include "qapi/error.h" 21e6eaabebSScott Wood #include "e500.h" 223eddc1beSBharat Bhushan #include "e500-ccsr.h" 231422e32dSPaolo Bonzini #include "net/net.h" 241de7afc9SPaolo Bonzini #include "qemu/config-file.h" 254a18e7c9SScott Wood #include "hw/hw.h" 260d09e41aSPaolo Bonzini #include "hw/char/serial.h" 27a2cb15b0SMichael S. Tsirkin #include "hw/pci/pci.h" 284a18e7c9SScott Wood #include "hw/boards.h" 299c17d615SPaolo Bonzini #include "sysemu/sysemu.h" 309c17d615SPaolo Bonzini #include "sysemu/kvm.h" 311db09b84Saurel32 #include "kvm_ppc.h" 329c17d615SPaolo Bonzini #include "sysemu/device_tree.h" 330d09e41aSPaolo Bonzini #include "hw/ppc/openpic.h" 348d085cf0SMark Cave-Ayland #include "hw/ppc/openpic_kvm.h" 350d09e41aSPaolo Bonzini #include "hw/ppc/ppc.h" 364a18e7c9SScott Wood #include "hw/loader.h" 37ca20cf32SBlue Swirl #include "elf.h" 384a18e7c9SScott Wood #include "hw/sysbus.h" 39022c62cbSPaolo Bonzini #include "exec/address-spaces.h" 401de7afc9SPaolo Bonzini #include "qemu/host-utils.h" 41922a01a0SMarkus Armbruster #include "qemu/option.h" 420d09e41aSPaolo Bonzini #include "hw/pci-host/ppce500.h" 43f7087343SAlexander Graf #include "qemu/error-report.h" 44f7087343SAlexander Graf #include "hw/platform-bus.h" 45fdfb7f2cSAlexander Graf #include "hw/net/fsl_etsec/etsec.h" 467abb479cSAndrew Randrianasulu #include "hw/i2c/i2c.h" 471db09b84Saurel32 48cefd3cdbSBharat Bhushan #define EPAPR_MAGIC (0x45504150) 491db09b84Saurel32 #define BINARY_DEVICE_TREE_FILE "mpc8544ds.dtb" 509dd5eba1SScott Wood #define DTC_LOAD_PAD 0x1800000 5175bb6589SLiu Yu #define DTC_PAD_MASK 0xFFFFF 52ab3dd749SPhilippe Mathieu-Daudé #define DTB_MAX_SIZE (8 * MiB) 5375bb6589SLiu Yu #define INITRD_LOAD_PAD 0x2000000 5475bb6589SLiu Yu #define INITRD_PAD_MASK 0xFFFFFF 551db09b84Saurel32 56ab3dd749SPhilippe Mathieu-Daudé #define RAM_SIZES_ALIGN (64 * MiB) 571db09b84Saurel32 58b3305981SScott Wood /* TODO: parameterize */ 59ed2bc496SAlexander Graf #define MPC8544_CCSRBAR_SIZE 0x00100000ULL 60dffb1dc2SBharat Bhushan #define MPC8544_MPIC_REGS_OFFSET 0x40000ULL 61a911b7a9SAlexander Graf #define MPC8544_MSI_REGS_OFFSET 0x41600ULL 62dffb1dc2SBharat Bhushan #define MPC8544_SERIAL0_REGS_OFFSET 0x4500ULL 63dffb1dc2SBharat Bhushan #define MPC8544_SERIAL1_REGS_OFFSET 0x4600ULL 64dffb1dc2SBharat Bhushan #define MPC8544_PCI_REGS_OFFSET 0x8000ULL 65ed2bc496SAlexander Graf #define MPC8544_PCI_REGS_SIZE 0x1000ULL 66dffb1dc2SBharat Bhushan #define MPC8544_UTIL_OFFSET 0xe0000ULL 67b88e77f4SAlexander Graf #define MPC8XXX_GPIO_OFFSET 0x000FF000ULL 687abb479cSAndrew Randrianasulu #define MPC8544_I2C_REGS_OFFSET 0x3000ULL 6982e345f5SAmit Tomar #define MPC8XXX_GPIO_IRQ 47 707abb479cSAndrew Randrianasulu #define MPC8544_I2C_IRQ 43 717abb479cSAndrew Randrianasulu #define RTC_REGS_OFFSET 0x68 721db09b84Saurel32 733b989d49SAlexander Graf struct boot_info 743b989d49SAlexander Graf { 753b989d49SAlexander Graf uint32_t dt_base; 76cba2026aSAlexander Graf uint32_t dt_size; 773b989d49SAlexander Graf uint32_t entry; 783b989d49SAlexander Graf }; 793b989d49SAlexander Graf 80347dd79dSAlexander Graf static uint32_t *pci_map_create(void *fdt, uint32_t mpic, int first_slot, 81347dd79dSAlexander Graf int nr_slots, int *len) 820dbc0798SAlexander Graf { 83347dd79dSAlexander Graf int i = 0; 84347dd79dSAlexander Graf int slot; 85347dd79dSAlexander Graf int pci_irq; 869e2c1298SAlexander Graf int host_irq; 87347dd79dSAlexander Graf int last_slot = first_slot + nr_slots; 88347dd79dSAlexander Graf uint32_t *pci_map; 890dbc0798SAlexander Graf 90347dd79dSAlexander Graf *len = nr_slots * 4 * 7 * sizeof(uint32_t); 91347dd79dSAlexander Graf pci_map = g_malloc(*len); 92347dd79dSAlexander Graf 93347dd79dSAlexander Graf for (slot = first_slot; slot < last_slot; slot++) { 94347dd79dSAlexander Graf for (pci_irq = 0; pci_irq < 4; pci_irq++) { 95347dd79dSAlexander Graf pci_map[i++] = cpu_to_be32(slot << 11); 96347dd79dSAlexander Graf pci_map[i++] = cpu_to_be32(0x0); 97347dd79dSAlexander Graf pci_map[i++] = cpu_to_be32(0x0); 98347dd79dSAlexander Graf pci_map[i++] = cpu_to_be32(pci_irq + 1); 99347dd79dSAlexander Graf pci_map[i++] = cpu_to_be32(mpic); 1009e2c1298SAlexander Graf host_irq = ppce500_pci_map_irq_slot(slot, pci_irq); 1019e2c1298SAlexander Graf pci_map[i++] = cpu_to_be32(host_irq + 1); 102347dd79dSAlexander Graf pci_map[i++] = cpu_to_be32(0x1); 1030dbc0798SAlexander Graf } 1040dbc0798SAlexander Graf } 1050dbc0798SAlexander Graf 106347dd79dSAlexander Graf assert((i * sizeof(uint32_t)) == *len); 107347dd79dSAlexander Graf 108347dd79dSAlexander Graf return pci_map; 109347dd79dSAlexander Graf } 110347dd79dSAlexander Graf 111a053a7ceSAlexander Graf static void dt_serial_create(void *fdt, unsigned long long offset, 112a053a7ceSAlexander Graf const char *soc, const char *mpic, 113a053a7ceSAlexander Graf const char *alias, int idx, bool defcon) 114a053a7ceSAlexander Graf { 1152fb513d3SGreg Kurz char *ser; 116a053a7ceSAlexander Graf 1172fb513d3SGreg Kurz ser = g_strdup_printf("%s/serial@%llx", soc, offset); 1185a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, ser); 1195a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, ser, "device_type", "serial"); 1205a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, ser, "compatible", "ns16550"); 1215a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, ser, "reg", offset, 0x100); 1225a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, ser, "cell-index", idx); 1235a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, ser, "clock-frequency", 0); 1245a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, ser, "interrupts", 42, 2); 1255a4348d1SPeter Crosthwaite qemu_fdt_setprop_phandle(fdt, ser, "interrupt-parent", mpic); 1265a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, "/aliases", alias, ser); 127a053a7ceSAlexander Graf 128a053a7ceSAlexander Graf if (defcon) { 12990ee4e01SNikunj A Dadhania /* 13090ee4e01SNikunj A Dadhania * "linux,stdout-path" and "stdout" properties are deprecated by linux 13190ee4e01SNikunj A Dadhania * kernel. New platforms should only use the "stdout-path" property. Set 13290ee4e01SNikunj A Dadhania * the new property and continue using older property to remain 13390ee4e01SNikunj A Dadhania * compatible with the existing firmware. 13490ee4e01SNikunj A Dadhania */ 1355a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, "/chosen", "linux,stdout-path", ser); 13690ee4e01SNikunj A Dadhania qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", ser); 137a053a7ceSAlexander Graf } 1382fb513d3SGreg Kurz g_free(ser); 139a053a7ceSAlexander Graf } 140a053a7ceSAlexander Graf 141b88e77f4SAlexander Graf static void create_dt_mpc8xxx_gpio(void *fdt, const char *soc, const char *mpic) 142b88e77f4SAlexander Graf { 143b88e77f4SAlexander Graf hwaddr mmio0 = MPC8XXX_GPIO_OFFSET; 144b88e77f4SAlexander Graf int irq0 = MPC8XXX_GPIO_IRQ; 145b88e77f4SAlexander Graf gchar *node = g_strdup_printf("%s/gpio@%"PRIx64, soc, mmio0); 146016f7758SAlexander Graf gchar *poweroff = g_strdup_printf("%s/power-off", soc); 147016f7758SAlexander Graf int gpio_ph; 148b88e77f4SAlexander Graf 149b88e77f4SAlexander Graf qemu_fdt_add_subnode(fdt, node); 150b88e77f4SAlexander Graf qemu_fdt_setprop_string(fdt, node, "compatible", "fsl,qoriq-gpio"); 151b88e77f4SAlexander Graf qemu_fdt_setprop_cells(fdt, node, "reg", mmio0, 0x1000); 152b88e77f4SAlexander Graf qemu_fdt_setprop_cells(fdt, node, "interrupts", irq0, 0x2); 153b88e77f4SAlexander Graf qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", mpic); 154b88e77f4SAlexander Graf qemu_fdt_setprop_cells(fdt, node, "#gpio-cells", 2); 155b88e77f4SAlexander Graf qemu_fdt_setprop(fdt, node, "gpio-controller", NULL, 0); 156016f7758SAlexander Graf gpio_ph = qemu_fdt_alloc_phandle(fdt); 157016f7758SAlexander Graf qemu_fdt_setprop_cell(fdt, node, "phandle", gpio_ph); 158016f7758SAlexander Graf qemu_fdt_setprop_cell(fdt, node, "linux,phandle", gpio_ph); 159016f7758SAlexander Graf 160016f7758SAlexander Graf /* Power Off Pin */ 161016f7758SAlexander Graf qemu_fdt_add_subnode(fdt, poweroff); 162016f7758SAlexander Graf qemu_fdt_setprop_string(fdt, poweroff, "compatible", "gpio-poweroff"); 163016f7758SAlexander Graf qemu_fdt_setprop_cells(fdt, poweroff, "gpios", gpio_ph, 0, 0); 164b88e77f4SAlexander Graf 165b88e77f4SAlexander Graf g_free(node); 166016f7758SAlexander Graf g_free(poweroff); 167b88e77f4SAlexander Graf } 168b88e77f4SAlexander Graf 1697abb479cSAndrew Randrianasulu static void dt_rtc_create(void *fdt, const char *i2c, const char *alias) 1707abb479cSAndrew Randrianasulu { 1717abb479cSAndrew Randrianasulu int offset = RTC_REGS_OFFSET; 1727abb479cSAndrew Randrianasulu 1737abb479cSAndrew Randrianasulu gchar *rtc = g_strdup_printf("%s/rtc@%"PRIx32, i2c, offset); 1747abb479cSAndrew Randrianasulu qemu_fdt_add_subnode(fdt, rtc); 1757abb479cSAndrew Randrianasulu qemu_fdt_setprop_string(fdt, rtc, "compatible", "pericom,pt7c4338"); 1767abb479cSAndrew Randrianasulu qemu_fdt_setprop_cells(fdt, rtc, "reg", offset); 1777abb479cSAndrew Randrianasulu qemu_fdt_setprop_string(fdt, "/aliases", alias, rtc); 1787abb479cSAndrew Randrianasulu 1797abb479cSAndrew Randrianasulu g_free(rtc); 1807abb479cSAndrew Randrianasulu } 1817abb479cSAndrew Randrianasulu 1827abb479cSAndrew Randrianasulu static void dt_i2c_create(void *fdt, const char *soc, const char *mpic, 1837abb479cSAndrew Randrianasulu const char *alias) 1847abb479cSAndrew Randrianasulu { 1857abb479cSAndrew Randrianasulu hwaddr mmio0 = MPC8544_I2C_REGS_OFFSET; 1867abb479cSAndrew Randrianasulu int irq0 = MPC8544_I2C_IRQ; 1877abb479cSAndrew Randrianasulu 1887abb479cSAndrew Randrianasulu gchar *i2c = g_strdup_printf("%s/i2c@%"PRIx64, soc, mmio0); 1897abb479cSAndrew Randrianasulu qemu_fdt_add_subnode(fdt, i2c); 1907abb479cSAndrew Randrianasulu qemu_fdt_setprop_string(fdt, i2c, "device_type", "i2c"); 1917abb479cSAndrew Randrianasulu qemu_fdt_setprop_string(fdt, i2c, "compatible", "fsl-i2c"); 1927abb479cSAndrew Randrianasulu qemu_fdt_setprop_cells(fdt, i2c, "reg", mmio0, 0x14); 1937abb479cSAndrew Randrianasulu qemu_fdt_setprop_cells(fdt, i2c, "cell-index", 0); 1947abb479cSAndrew Randrianasulu qemu_fdt_setprop_cells(fdt, i2c, "interrupts", irq0, 0x2); 1957abb479cSAndrew Randrianasulu qemu_fdt_setprop_phandle(fdt, i2c, "interrupt-parent", mpic); 1967abb479cSAndrew Randrianasulu qemu_fdt_setprop_string(fdt, "/aliases", alias, i2c); 1977abb479cSAndrew Randrianasulu 1987abb479cSAndrew Randrianasulu g_free(i2c); 1997abb479cSAndrew Randrianasulu } 2007abb479cSAndrew Randrianasulu 2017abb479cSAndrew Randrianasulu 202f7087343SAlexander Graf typedef struct PlatformDevtreeData { 203f7087343SAlexander Graf void *fdt; 204f7087343SAlexander Graf const char *mpic; 205f7087343SAlexander Graf int irq_start; 206f7087343SAlexander Graf const char *node; 207f7087343SAlexander Graf PlatformBusDevice *pbus; 208f7087343SAlexander Graf } PlatformDevtreeData; 209f7087343SAlexander Graf 210fdfb7f2cSAlexander Graf static int create_devtree_etsec(SysBusDevice *sbdev, PlatformDevtreeData *data) 211fdfb7f2cSAlexander Graf { 212fdfb7f2cSAlexander Graf eTSEC *etsec = ETSEC_COMMON(sbdev); 213fdfb7f2cSAlexander Graf PlatformBusDevice *pbus = data->pbus; 214fdfb7f2cSAlexander Graf hwaddr mmio0 = platform_bus_get_mmio_addr(pbus, sbdev, 0); 215fdfb7f2cSAlexander Graf int irq0 = platform_bus_get_irqn(pbus, sbdev, 0); 216fdfb7f2cSAlexander Graf int irq1 = platform_bus_get_irqn(pbus, sbdev, 1); 217fdfb7f2cSAlexander Graf int irq2 = platform_bus_get_irqn(pbus, sbdev, 2); 218fdfb7f2cSAlexander Graf gchar *node = g_strdup_printf("/platform/ethernet@%"PRIx64, mmio0); 219fdfb7f2cSAlexander Graf gchar *group = g_strdup_printf("%s/queue-group", node); 220fdfb7f2cSAlexander Graf void *fdt = data->fdt; 221fdfb7f2cSAlexander Graf 222fdfb7f2cSAlexander Graf assert((int64_t)mmio0 >= 0); 223fdfb7f2cSAlexander Graf assert(irq0 >= 0); 224fdfb7f2cSAlexander Graf assert(irq1 >= 0); 225fdfb7f2cSAlexander Graf assert(irq2 >= 0); 226fdfb7f2cSAlexander Graf 227fdfb7f2cSAlexander Graf qemu_fdt_add_subnode(fdt, node); 228fdfb7f2cSAlexander Graf qemu_fdt_setprop_string(fdt, node, "device_type", "network"); 229fdfb7f2cSAlexander Graf qemu_fdt_setprop_string(fdt, node, "compatible", "fsl,etsec2"); 230fdfb7f2cSAlexander Graf qemu_fdt_setprop_string(fdt, node, "model", "eTSEC"); 231fdfb7f2cSAlexander Graf qemu_fdt_setprop(fdt, node, "local-mac-address", etsec->conf.macaddr.a, 6); 232fdfb7f2cSAlexander Graf qemu_fdt_setprop_cells(fdt, node, "fixed-link", 0, 1, 1000, 0, 0); 233fdfb7f2cSAlexander Graf 234fdfb7f2cSAlexander Graf qemu_fdt_add_subnode(fdt, group); 235fdfb7f2cSAlexander Graf qemu_fdt_setprop_cells(fdt, group, "reg", mmio0, 0x1000); 236fdfb7f2cSAlexander Graf qemu_fdt_setprop_cells(fdt, group, "interrupts", 237fdfb7f2cSAlexander Graf data->irq_start + irq0, 0x2, 238fdfb7f2cSAlexander Graf data->irq_start + irq1, 0x2, 239fdfb7f2cSAlexander Graf data->irq_start + irq2, 0x2); 240fdfb7f2cSAlexander Graf 241fdfb7f2cSAlexander Graf g_free(node); 242fdfb7f2cSAlexander Graf g_free(group); 243fdfb7f2cSAlexander Graf 244fdfb7f2cSAlexander Graf return 0; 245fdfb7f2cSAlexander Graf } 246fdfb7f2cSAlexander Graf 2474f01a637SDavid Gibson static void sysbus_device_create_devtree(SysBusDevice *sbdev, void *opaque) 248f7087343SAlexander Graf { 249f7087343SAlexander Graf PlatformDevtreeData *data = opaque; 250f7087343SAlexander Graf bool matched = false; 251f7087343SAlexander Graf 252fdfb7f2cSAlexander Graf if (object_dynamic_cast(OBJECT(sbdev), TYPE_ETSEC_COMMON)) { 253fdfb7f2cSAlexander Graf create_devtree_etsec(sbdev, data); 254fdfb7f2cSAlexander Graf matched = true; 255fdfb7f2cSAlexander Graf } 256fdfb7f2cSAlexander Graf 257f7087343SAlexander Graf if (!matched) { 258f7087343SAlexander Graf error_report("Device %s is not supported by this machine yet.", 259f7087343SAlexander Graf qdev_fw_name(DEVICE(sbdev))); 260f7087343SAlexander Graf exit(1); 261f7087343SAlexander Graf } 262f7087343SAlexander Graf } 263f7087343SAlexander Graf 264a3fc8396SIgor Mammedov static void platform_bus_create_devtree(PPCE500MachineState *pms, 26503f04809SIgor Mammedov void *fdt, const char *mpic) 266f7087343SAlexander Graf { 267a3fc8396SIgor Mammedov const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(pms); 26803f04809SIgor Mammedov gchar *node = g_strdup_printf("/platform@%"PRIx64, pmc->platform_bus_base); 269f7087343SAlexander Graf const char platcomp[] = "qemu,platform\0simple-bus"; 27003f04809SIgor Mammedov uint64_t addr = pmc->platform_bus_base; 27103f04809SIgor Mammedov uint64_t size = pmc->platform_bus_size; 27203f04809SIgor Mammedov int irq_start = pmc->platform_bus_first_irq; 273f7087343SAlexander Graf 274f7087343SAlexander Graf /* Create a /platform node that we can put all devices into */ 275f7087343SAlexander Graf 276f7087343SAlexander Graf qemu_fdt_add_subnode(fdt, node); 277f7087343SAlexander Graf qemu_fdt_setprop(fdt, node, "compatible", platcomp, sizeof(platcomp)); 278f7087343SAlexander Graf 279f7087343SAlexander Graf /* Our platform bus region is less than 32bit big, so 1 cell is enough for 280f7087343SAlexander Graf address and size */ 281f7087343SAlexander Graf qemu_fdt_setprop_cells(fdt, node, "#size-cells", 1); 282f7087343SAlexander Graf qemu_fdt_setprop_cells(fdt, node, "#address-cells", 1); 283f7087343SAlexander Graf qemu_fdt_setprop_cells(fdt, node, "ranges", 0, addr >> 32, addr, size); 284f7087343SAlexander Graf 285f7087343SAlexander Graf qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", mpic); 286f7087343SAlexander Graf 287a3fc8396SIgor Mammedov /* Create dt nodes for dynamic devices */ 288f7087343SAlexander Graf PlatformDevtreeData data = { 289f7087343SAlexander Graf .fdt = fdt, 290f7087343SAlexander Graf .mpic = mpic, 291f7087343SAlexander Graf .irq_start = irq_start, 292f7087343SAlexander Graf .node = node, 293a3fc8396SIgor Mammedov .pbus = pms->pbus_dev, 294f7087343SAlexander Graf }; 295f7087343SAlexander Graf 296f7087343SAlexander Graf /* Loop through all dynamic sysbus devices and create nodes for them */ 297f7087343SAlexander Graf foreach_dynamic_sysbus_device(sysbus_device_create_devtree, &data); 298f7087343SAlexander Graf 299f7087343SAlexander Graf g_free(node); 300f7087343SAlexander Graf } 301f7087343SAlexander Graf 30203f04809SIgor Mammedov static int ppce500_load_device_tree(PPCE500MachineState *pms, 303a8170e5eSAvi Kivity hwaddr addr, 304a8170e5eSAvi Kivity hwaddr initrd_base, 30528290f37SAlexander Graf hwaddr initrd_size, 306903585deSAlexander Graf hwaddr kernel_base, 307903585deSAlexander Graf hwaddr kernel_size, 30828290f37SAlexander Graf bool dry_run) 3091db09b84Saurel32 { 31003f04809SIgor Mammedov MachineState *machine = MACHINE(pms); 31103f04809SIgor Mammedov const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(pms); 31228290f37SAlexander Graf CPUPPCState *env = first_cpu->env_ptr; 313dbf916d8SAurelien Jarno int ret = -1; 3143ef96221SMarcel Apfelbaum uint64_t mem_reg_property[] = { 0, cpu_to_be64(machine->ram_size) }; 3157ec632b4Spbrook int fdt_size; 316dbf916d8SAurelien Jarno void *fdt; 3175de6b46dSAlexander Graf uint8_t hypercall[16]; 318911d6e7aSAlexander Graf uint32_t clock_freq = 400000000; 319911d6e7aSAlexander Graf uint32_t tb_freq = 400000000; 320621d05e3SAlexander Graf int i; 321ebb9518aSAlexander Graf char compatible_sb[] = "fsl,mpc8544-immr\0simple-bus"; 3222fb513d3SGreg Kurz char *soc; 3232fb513d3SGreg Kurz char *mpic; 32419ac9deaSAlexander Graf uint32_t mpic_ph; 325a911b7a9SAlexander Graf uint32_t msi_ph; 3262fb513d3SGreg Kurz char *gutil; 3272fb513d3SGreg Kurz char *pci; 3282fb513d3SGreg Kurz char *msi; 329347dd79dSAlexander Graf uint32_t *pci_map = NULL; 330347dd79dSAlexander Graf int len; 3313627757eSAlexander Graf uint32_t pci_ranges[14] = 3323627757eSAlexander Graf { 33303f04809SIgor Mammedov 0x2000000, 0x0, pmc->pci_mmio_bus_base, 33403f04809SIgor Mammedov pmc->pci_mmio_base >> 32, pmc->pci_mmio_base, 3353627757eSAlexander Graf 0x0, 0x20000000, 3363627757eSAlexander Graf 3373627757eSAlexander Graf 0x1000000, 0x0, 0x0, 33803f04809SIgor Mammedov pmc->pci_pio_base >> 32, pmc->pci_pio_base, 3393627757eSAlexander Graf 0x0, 0x10000, 3403627757eSAlexander Graf }; 3412ff3de68SMarkus Armbruster QemuOpts *machine_opts = qemu_get_machine_opts(); 3422ff3de68SMarkus Armbruster const char *dtb_file = qemu_opt_get(machine_opts, "dtb"); 3432ff3de68SMarkus Armbruster const char *toplevel_compat = qemu_opt_get(machine_opts, "dt_compatible"); 344d1b93565SAlexander Graf 345d1b93565SAlexander Graf if (dtb_file) { 346d1b93565SAlexander Graf char *filename; 347d1b93565SAlexander Graf filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_file); 348d1b93565SAlexander Graf if (!filename) { 349d1b93565SAlexander Graf goto out; 350d1b93565SAlexander Graf } 351d1b93565SAlexander Graf 352d1b93565SAlexander Graf fdt = load_device_tree(filename, &fdt_size); 3532343dd11SMichael Tokarev g_free(filename); 354d1b93565SAlexander Graf if (!fdt) { 355d1b93565SAlexander Graf goto out; 356d1b93565SAlexander Graf } 357d1b93565SAlexander Graf goto done; 358d1b93565SAlexander Graf } 3591db09b84Saurel32 3602636fcb6SAlexander Graf fdt = create_device_tree(&fdt_size); 3615cea8590SPaul Brook if (fdt == NULL) { 3625cea8590SPaul Brook goto out; 3635cea8590SPaul Brook } 3641db09b84Saurel32 3651db09b84Saurel32 /* Manipulate device tree in memory. */ 3665a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 2); 3675a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 2); 36851b852b7SAlexander Graf 3695a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, "/memory"); 3705a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, "/memory", "device_type", "memory"); 3715a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, "/memory", "reg", mem_reg_property, 3721db09b84Saurel32 sizeof(mem_reg_property)); 3731db09b84Saurel32 3745a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, "/chosen"); 3753b989d49SAlexander Graf if (initrd_size) { 3765a4348d1SPeter Crosthwaite ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start", 3771db09b84Saurel32 initrd_base); 3783b989d49SAlexander Graf if (ret < 0) { 3791db09b84Saurel32 fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n"); 3803b989d49SAlexander Graf } 3811db09b84Saurel32 3825a4348d1SPeter Crosthwaite ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end", 3831db09b84Saurel32 (initrd_base + initrd_size)); 3843b989d49SAlexander Graf if (ret < 0) { 3851db09b84Saurel32 fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n"); 3863b989d49SAlexander Graf } 387903585deSAlexander Graf 388903585deSAlexander Graf } 389903585deSAlexander Graf 390903585deSAlexander Graf if (kernel_base != -1ULL) { 391903585deSAlexander Graf qemu_fdt_setprop_cells(fdt, "/chosen", "qemu,boot-kernel", 392903585deSAlexander Graf kernel_base >> 32, kernel_base, 393903585deSAlexander Graf kernel_size >> 32, kernel_size); 3943b989d49SAlexander Graf } 3951db09b84Saurel32 3965a4348d1SPeter Crosthwaite ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", 3973ef96221SMarcel Apfelbaum machine->kernel_cmdline); 3981db09b84Saurel32 if (ret < 0) 3991db09b84Saurel32 fprintf(stderr, "couldn't set /chosen/bootargs\n"); 4001db09b84Saurel32 4011db09b84Saurel32 if (kvm_enabled()) { 402911d6e7aSAlexander Graf /* Read out host's frequencies */ 403911d6e7aSAlexander Graf clock_freq = kvmppc_get_clockfreq(); 404911d6e7aSAlexander Graf tb_freq = kvmppc_get_tbfreq(); 4055de6b46dSAlexander Graf 4065de6b46dSAlexander Graf /* indicate KVM hypercall interface */ 4075a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, "/hypervisor"); 4085a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, "/hypervisor", "compatible", 4095de6b46dSAlexander Graf "linux,kvm"); 4105de6b46dSAlexander Graf kvmppc_get_hypercall(env, hypercall, sizeof(hypercall)); 4115a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, "/hypervisor", "hcall-instructions", 4125de6b46dSAlexander Graf hypercall, sizeof(hypercall)); 4131a61a9aeSStuart Yoder /* if KVM supports the idle hcall, set property indicating this */ 4141a61a9aeSStuart Yoder if (kvmppc_get_hasidle(env)) { 4155a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, "/hypervisor", "has-idle", NULL, 0); 4161a61a9aeSStuart Yoder } 4171db09b84Saurel32 } 4181db09b84Saurel32 419625e665bSAlexander Graf /* Create CPU nodes */ 4205a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, "/cpus"); 4215a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 1); 4225a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0); 423625e665bSAlexander Graf 4241e3debf0SAlexander Graf /* We need to generate the cpu nodes in reverse order, so Linux can pick 4251e3debf0SAlexander Graf the first node as boot node and be happy */ 4261e3debf0SAlexander Graf for (i = smp_cpus - 1; i >= 0; i--) { 427440c8152SAndreas Färber CPUState *cpu; 4282fb513d3SGreg Kurz char *cpu_name; 42903f04809SIgor Mammedov uint64_t cpu_release_addr = pmc->spin_base + (i * 0x20); 43010f25a46SAlexander Graf 431440c8152SAndreas Färber cpu = qemu_get_cpu(i); 43255e5c285SAndreas Färber if (cpu == NULL) { 4331e3debf0SAlexander Graf continue; 4341e3debf0SAlexander Graf } 435440c8152SAndreas Färber env = cpu->env_ptr; 4361e3debf0SAlexander Graf 4372fb513d3SGreg Kurz cpu_name = g_strdup_printf("/cpus/PowerPC,8544@%x", i); 4385a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, cpu_name); 4395a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq); 4405a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq); 4415a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, cpu_name, "device_type", "cpu"); 4426d536570SSam Bobroff qemu_fdt_setprop_cell(fdt, cpu_name, "reg", i); 4435a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-line-size", 4441e3debf0SAlexander Graf env->dcache_line_size); 4455a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-line-size", 4461e3debf0SAlexander Graf env->icache_line_size); 4475a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-size", 0x8000); 4485a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-size", 0x8000); 4495a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "bus-frequency", 0); 45055e5c285SAndreas Färber if (cpu->cpu_index) { 4515a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, cpu_name, "status", "disabled"); 4525a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, cpu_name, "enable-method", 4535a4348d1SPeter Crosthwaite "spin-table"); 4545a4348d1SPeter Crosthwaite qemu_fdt_setprop_u64(fdt, cpu_name, "cpu-release-addr", 4551d2e5c52SAlexander Graf cpu_release_addr); 4561e3debf0SAlexander Graf } else { 4575a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, cpu_name, "status", "okay"); 4581e3debf0SAlexander Graf } 4592fb513d3SGreg Kurz g_free(cpu_name); 4601db09b84Saurel32 } 4611db09b84Saurel32 4625a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, "/aliases"); 4635da96624SAlexander Graf /* XXX These should go into their respective devices' code */ 4642fb513d3SGreg Kurz soc = g_strdup_printf("/soc@%"PRIx64, pmc->ccsrbar_base); 4655a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, soc); 4665a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, soc, "device_type", "soc"); 4675a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, soc, "compatible", compatible_sb, 468ebb9518aSAlexander Graf sizeof(compatible_sb)); 4695a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, soc, "#address-cells", 1); 4705a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, soc, "#size-cells", 1); 4715a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, soc, "ranges", 0x0, 47203f04809SIgor Mammedov pmc->ccsrbar_base >> 32, pmc->ccsrbar_base, 4735da96624SAlexander Graf MPC8544_CCSRBAR_SIZE); 4745da96624SAlexander Graf /* XXX should contain a reasonable value */ 4755a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, soc, "bus-frequency", 0); 4765da96624SAlexander Graf 4772fb513d3SGreg Kurz mpic = g_strdup_printf("%s/pic@%llx", soc, MPC8544_MPIC_REGS_OFFSET); 4785a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, mpic); 4795a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, mpic, "device_type", "open-pic"); 4805a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, mpic, "compatible", "fsl,mpic"); 4815a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_OFFSET, 482dffb1dc2SBharat Bhushan 0x40000); 4835a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, mpic, "#address-cells", 0); 4845a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, mpic, "#interrupt-cells", 2); 4855a4348d1SPeter Crosthwaite mpic_ph = qemu_fdt_alloc_phandle(fdt); 4865a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, mpic, "phandle", mpic_ph); 4875a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, mpic, "linux,phandle", mpic_ph); 4885a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, mpic, "interrupt-controller", NULL, 0); 48919ac9deaSAlexander Graf 4900cfc6e8dSAlexander Graf /* 4910cfc6e8dSAlexander Graf * We have to generate ser1 first, because Linux takes the first 4920cfc6e8dSAlexander Graf * device it finds in the dt as serial output device. And we generate 4930cfc6e8dSAlexander Graf * devices in reverse order to the dt. 4940cfc6e8dSAlexander Graf */ 4959bca0edbSPeter Maydell if (serial_hd(1)) { 496dffb1dc2SBharat Bhushan dt_serial_create(fdt, MPC8544_SERIAL1_REGS_OFFSET, 497a053a7ceSAlexander Graf soc, mpic, "serial1", 1, false); 49879c0ff2cSAlexander Graf } 49979c0ff2cSAlexander Graf 5009bca0edbSPeter Maydell if (serial_hd(0)) { 501dffb1dc2SBharat Bhushan dt_serial_create(fdt, MPC8544_SERIAL0_REGS_OFFSET, 502a053a7ceSAlexander Graf soc, mpic, "serial0", 0, true); 50379c0ff2cSAlexander Graf } 5040cfc6e8dSAlexander Graf 5057abb479cSAndrew Randrianasulu /* i2c */ 5067abb479cSAndrew Randrianasulu dt_i2c_create(fdt, soc, mpic, "i2c"); 5077abb479cSAndrew Randrianasulu 5087abb479cSAndrew Randrianasulu dt_rtc_create(fdt, "i2c", "rtc"); 5097abb479cSAndrew Randrianasulu 5107abb479cSAndrew Randrianasulu 5112fb513d3SGreg Kurz gutil = g_strdup_printf("%s/global-utilities@%llx", soc, 512dffb1dc2SBharat Bhushan MPC8544_UTIL_OFFSET); 5135a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, gutil); 5145a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, gutil, "compatible", "fsl,mpc8544-guts"); 5155a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, gutil, "reg", MPC8544_UTIL_OFFSET, 0x1000); 5165a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, gutil, "fsl,has-rstcr", NULL, 0); 5172fb513d3SGreg Kurz g_free(gutil); 518f5038483SAlexander Graf 5192fb513d3SGreg Kurz msi = g_strdup_printf("/%s/msi@%llx", soc, MPC8544_MSI_REGS_OFFSET); 5205a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, msi); 5215a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, msi, "compatible", "fsl,mpic-msi"); 5225a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, msi, "reg", MPC8544_MSI_REGS_OFFSET, 0x200); 5235a4348d1SPeter Crosthwaite msi_ph = qemu_fdt_alloc_phandle(fdt); 5245a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, msi, "msi-available-ranges", 0x0, 0x100); 5255a4348d1SPeter Crosthwaite qemu_fdt_setprop_phandle(fdt, msi, "interrupt-parent", mpic); 5265a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, msi, "interrupts", 527a911b7a9SAlexander Graf 0xe0, 0x0, 528a911b7a9SAlexander Graf 0xe1, 0x0, 529a911b7a9SAlexander Graf 0xe2, 0x0, 530a911b7a9SAlexander Graf 0xe3, 0x0, 531a911b7a9SAlexander Graf 0xe4, 0x0, 532a911b7a9SAlexander Graf 0xe5, 0x0, 533a911b7a9SAlexander Graf 0xe6, 0x0, 534a911b7a9SAlexander Graf 0xe7, 0x0); 5355a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, msi, "phandle", msi_ph); 5365a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, msi, "linux,phandle", msi_ph); 5372fb513d3SGreg Kurz g_free(msi); 538a911b7a9SAlexander Graf 5392fb513d3SGreg Kurz pci = g_strdup_printf("/pci@%llx", 54003f04809SIgor Mammedov pmc->ccsrbar_base + MPC8544_PCI_REGS_OFFSET); 5415a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, pci); 5425a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, pci, "cell-index", 0); 5435a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, pci, "compatible", "fsl,mpc8540-pci"); 5445a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, pci, "device_type", "pci"); 5455a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, pci, "interrupt-map-mask", 0xf800, 0x0, 5460dbc0798SAlexander Graf 0x0, 0x7); 5475a4348d1SPeter Crosthwaite pci_map = pci_map_create(fdt, qemu_fdt_get_phandle(fdt, mpic), 54803f04809SIgor Mammedov pmc->pci_first_slot, pmc->pci_nr_slots, 549492ec48dSAlexander Graf &len); 5505a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, pci, "interrupt-map", pci_map, len); 5515a4348d1SPeter Crosthwaite qemu_fdt_setprop_phandle(fdt, pci, "interrupt-parent", mpic); 5525a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, pci, "interrupts", 24, 2); 5535a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, pci, "bus-range", 0, 255); 5543627757eSAlexander Graf for (i = 0; i < 14; i++) { 5550dbc0798SAlexander Graf pci_ranges[i] = cpu_to_be32(pci_ranges[i]); 5560dbc0798SAlexander Graf } 5575a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, pci, "fsl,msi", msi_ph); 5585a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, pci, "ranges", pci_ranges, sizeof(pci_ranges)); 5592eaaac1fSAlexander Graf qemu_fdt_setprop_cells(fdt, pci, "reg", 56003f04809SIgor Mammedov (pmc->ccsrbar_base + MPC8544_PCI_REGS_OFFSET) >> 32, 56103f04809SIgor Mammedov (pmc->ccsrbar_base + MPC8544_PCI_REGS_OFFSET), 5622eaaac1fSAlexander Graf 0, 0x1000); 5635a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, pci, "clock-frequency", 66666666); 5645a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, pci, "#interrupt-cells", 1); 5655a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, pci, "#size-cells", 2); 5665a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, pci, "#address-cells", 3); 5675a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, "/aliases", "pci0", pci); 5682fb513d3SGreg Kurz g_free(pci); 5690dbc0798SAlexander Graf 57003f04809SIgor Mammedov if (pmc->has_mpc8xxx_gpio) { 571b88e77f4SAlexander Graf create_dt_mpc8xxx_gpio(fdt, soc, mpic); 572b88e77f4SAlexander Graf } 5732fb513d3SGreg Kurz g_free(soc); 574b88e77f4SAlexander Graf 575a3fc8396SIgor Mammedov if (pms->pbus_dev) { 576a3fc8396SIgor Mammedov platform_bus_create_devtree(pms, fdt, mpic); 577f7087343SAlexander Graf } 5782fb513d3SGreg Kurz g_free(mpic); 579f7087343SAlexander Graf 58003f04809SIgor Mammedov pmc->fixup_devtree(fdt); 581e6eaabebSScott Wood 582e6eaabebSScott Wood if (toplevel_compat) { 5835a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, "/", "compatible", toplevel_compat, 584e6eaabebSScott Wood strlen(toplevel_compat) + 1); 585e6eaabebSScott Wood } 586e6eaabebSScott Wood 587d1b93565SAlexander Graf done: 58828290f37SAlexander Graf if (!dry_run) { 5895a4348d1SPeter Crosthwaite qemu_fdt_dumpdtb(fdt, fdt_size); 59028290f37SAlexander Graf cpu_physical_memory_write(addr, fdt, fdt_size); 591cba2026aSAlexander Graf } 592cba2026aSAlexander Graf ret = fdt_size; 5937ec632b4Spbrook 5941db09b84Saurel32 out: 595347dd79dSAlexander Graf g_free(pci_map); 5961db09b84Saurel32 59704088adbSLiu Yu return ret; 5981db09b84Saurel32 } 5991db09b84Saurel32 60028290f37SAlexander Graf typedef struct DeviceTreeParams { 60103f04809SIgor Mammedov PPCE500MachineState *machine; 60228290f37SAlexander Graf hwaddr addr; 60328290f37SAlexander Graf hwaddr initrd_base; 60428290f37SAlexander Graf hwaddr initrd_size; 605903585deSAlexander Graf hwaddr kernel_base; 606903585deSAlexander Graf hwaddr kernel_size; 607f7087343SAlexander Graf Notifier notifier; 60828290f37SAlexander Graf } DeviceTreeParams; 60928290f37SAlexander Graf 61028290f37SAlexander Graf static void ppce500_reset_device_tree(void *opaque) 61128290f37SAlexander Graf { 61228290f37SAlexander Graf DeviceTreeParams *p = opaque; 61303f04809SIgor Mammedov ppce500_load_device_tree(p->machine, p->addr, p->initrd_base, 614903585deSAlexander Graf p->initrd_size, p->kernel_base, p->kernel_size, 615903585deSAlexander Graf false); 61628290f37SAlexander Graf } 61728290f37SAlexander Graf 618f7087343SAlexander Graf static void ppce500_init_notify(Notifier *notifier, void *data) 619f7087343SAlexander Graf { 620f7087343SAlexander Graf DeviceTreeParams *p = container_of(notifier, DeviceTreeParams, notifier); 621f7087343SAlexander Graf ppce500_reset_device_tree(p); 622f7087343SAlexander Graf } 623f7087343SAlexander Graf 62403f04809SIgor Mammedov static int ppce500_prep_device_tree(PPCE500MachineState *machine, 62528290f37SAlexander Graf hwaddr addr, 62628290f37SAlexander Graf hwaddr initrd_base, 627903585deSAlexander Graf hwaddr initrd_size, 628903585deSAlexander Graf hwaddr kernel_base, 629903585deSAlexander Graf hwaddr kernel_size) 63028290f37SAlexander Graf { 63128290f37SAlexander Graf DeviceTreeParams *p = g_new(DeviceTreeParams, 1); 6323ef96221SMarcel Apfelbaum p->machine = machine; 63328290f37SAlexander Graf p->addr = addr; 63428290f37SAlexander Graf p->initrd_base = initrd_base; 63528290f37SAlexander Graf p->initrd_size = initrd_size; 636903585deSAlexander Graf p->kernel_base = kernel_base; 637903585deSAlexander Graf p->kernel_size = kernel_size; 63828290f37SAlexander Graf 63928290f37SAlexander Graf qemu_register_reset(ppce500_reset_device_tree, p); 640f7087343SAlexander Graf p->notifier.notify = ppce500_init_notify; 641f7087343SAlexander Graf qemu_add_machine_init_done_notifier(&p->notifier); 64228290f37SAlexander Graf 64328290f37SAlexander Graf /* Issue the device tree loader once, so that we get the size of the blob */ 64403f04809SIgor Mammedov return ppce500_load_device_tree(machine, addr, initrd_base, initrd_size, 64503f04809SIgor Mammedov kernel_base, kernel_size, true); 64628290f37SAlexander Graf } 64728290f37SAlexander Graf 648cba2026aSAlexander Graf /* Create -kernel TLB entries for BookE. */ 649a36848ffSAaron Larson hwaddr booke206_page_size_to_tlb(uint64_t size) 650d1e256feSAlexander Graf { 651ab3dd749SPhilippe Mathieu-Daudé return 63 - clz64(size / KiB); 652d1e256feSAlexander Graf } 653d1e256feSAlexander Graf 654cefd3cdbSBharat Bhushan static int booke206_initial_map_tsize(CPUPPCState *env) 6553b989d49SAlexander Graf { 656cba2026aSAlexander Graf struct boot_info *bi = env->load_info; 657cefd3cdbSBharat Bhushan hwaddr dt_end; 658cba2026aSAlexander Graf int ps; 6593b989d49SAlexander Graf 660cba2026aSAlexander Graf /* Our initial TLB entry needs to cover everything from 0 to 661cba2026aSAlexander Graf the device tree top */ 662cba2026aSAlexander Graf dt_end = bi->dt_base + bi->dt_size; 663cba2026aSAlexander Graf ps = booke206_page_size_to_tlb(dt_end) + 1; 664fb37c302SAlexander Graf if (ps & 1) { 665fb37c302SAlexander Graf /* e500v2 can only do even TLB size bits */ 666fb37c302SAlexander Graf ps++; 667fb37c302SAlexander Graf } 668cefd3cdbSBharat Bhushan return ps; 669cefd3cdbSBharat Bhushan } 670cefd3cdbSBharat Bhushan 671cefd3cdbSBharat Bhushan static uint64_t mmubooke_initial_mapsize(CPUPPCState *env) 672cefd3cdbSBharat Bhushan { 673cefd3cdbSBharat Bhushan int tsize; 674cefd3cdbSBharat Bhushan 675cefd3cdbSBharat Bhushan tsize = booke206_initial_map_tsize(env); 676cefd3cdbSBharat Bhushan return (1ULL << 10 << tsize); 677cefd3cdbSBharat Bhushan } 678cefd3cdbSBharat Bhushan 679cefd3cdbSBharat Bhushan static void mmubooke_create_initial_mapping(CPUPPCState *env) 680cefd3cdbSBharat Bhushan { 681cefd3cdbSBharat Bhushan ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0); 682cefd3cdbSBharat Bhushan hwaddr size; 683cefd3cdbSBharat Bhushan int ps; 684cefd3cdbSBharat Bhushan 685cefd3cdbSBharat Bhushan ps = booke206_initial_map_tsize(env); 686cba2026aSAlexander Graf size = (ps << MAS1_TSIZE_SHIFT); 687d1e256feSAlexander Graf tlb->mas1 = MAS1_VALID | size; 688cba2026aSAlexander Graf tlb->mas2 = 0; 689cba2026aSAlexander Graf tlb->mas7_3 = 0; 690d1e256feSAlexander Graf tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX; 69193dd5e85SScott Wood 69293dd5e85SScott Wood env->tlb_dirty = true; 6933b989d49SAlexander Graf } 6943b989d49SAlexander Graf 695b3305981SScott Wood static void ppce500_cpu_reset_sec(void *opaque) 6965c145dacSAlexander Graf { 69738f92da6SAndreas Färber PowerPCCPU *cpu = opaque; 698259186a7SAndreas Färber CPUState *cs = CPU(cpu); 6995c145dacSAlexander Graf 700259186a7SAndreas Färber cpu_reset(cs); 7015c145dacSAlexander Graf 7025c145dacSAlexander Graf /* Secondary CPU starts in halted state for now. Needs to change when 7035c145dacSAlexander Graf implementing non-kernel boot. */ 704259186a7SAndreas Färber cs->halted = 1; 70527103424SAndreas Färber cs->exception_index = EXCP_HLT; 7063b989d49SAlexander Graf } 7073b989d49SAlexander Graf 708b3305981SScott Wood static void ppce500_cpu_reset(void *opaque) 7093b989d49SAlexander Graf { 71038f92da6SAndreas Färber PowerPCCPU *cpu = opaque; 711259186a7SAndreas Färber CPUState *cs = CPU(cpu); 71238f92da6SAndreas Färber CPUPPCState *env = &cpu->env; 7133b989d49SAlexander Graf struct boot_info *bi = env->load_info; 7143b989d49SAlexander Graf 715259186a7SAndreas Färber cpu_reset(cs); 7163b989d49SAlexander Graf 7173b989d49SAlexander Graf /* Set initial guest state. */ 718259186a7SAndreas Färber cs->halted = 0; 719ab3dd749SPhilippe Mathieu-Daudé env->gpr[1] = (16 * MiB) - 8; 7203b989d49SAlexander Graf env->gpr[3] = bi->dt_base; 721cefd3cdbSBharat Bhushan env->gpr[4] = 0; 722cefd3cdbSBharat Bhushan env->gpr[5] = 0; 723cefd3cdbSBharat Bhushan env->gpr[6] = EPAPR_MAGIC; 724cefd3cdbSBharat Bhushan env->gpr[7] = mmubooke_initial_mapsize(env); 725cefd3cdbSBharat Bhushan env->gpr[8] = 0; 726cefd3cdbSBharat Bhushan env->gpr[9] = 0; 7273b989d49SAlexander Graf env->nip = bi->entry; 728cba2026aSAlexander Graf mmubooke_create_initial_mapping(env); 7293b989d49SAlexander Graf } 7303b989d49SAlexander Graf 73103f04809SIgor Mammedov static DeviceState *ppce500_init_mpic_qemu(PPCE500MachineState *pms, 7322104d4f5SGreg Kurz IrqLines *irqs) 73382fc73b6SScott Wood { 73482fc73b6SScott Wood DeviceState *dev; 73582fc73b6SScott Wood SysBusDevice *s; 73682fc73b6SScott Wood int i, j, k; 73703f04809SIgor Mammedov MachineState *machine = MACHINE(pms); 73803f04809SIgor Mammedov const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(pms); 73982fc73b6SScott Wood 740e1766344SAndreas Färber dev = qdev_create(NULL, TYPE_OPENPIC); 74103f04809SIgor Mammedov object_property_add_child(OBJECT(machine), "pic", OBJECT(dev), 742e75ce32aSMichael Davidsaver &error_fatal); 74303f04809SIgor Mammedov qdev_prop_set_uint32(dev, "model", pmc->mpic_version); 744d85937e6SScott Wood qdev_prop_set_uint32(dev, "nb_cpus", smp_cpus); 745d85937e6SScott Wood 74682fc73b6SScott Wood qdev_init_nofail(dev); 74782fc73b6SScott Wood s = SYS_BUS_DEVICE(dev); 74882fc73b6SScott Wood 74982fc73b6SScott Wood k = 0; 75082fc73b6SScott Wood for (i = 0; i < smp_cpus; i++) { 75182fc73b6SScott Wood for (j = 0; j < OPENPIC_OUTPUT_NB; j++) { 7522104d4f5SGreg Kurz sysbus_connect_irq(s, k++, irqs[i].irq[j]); 75382fc73b6SScott Wood } 75482fc73b6SScott Wood } 75582fc73b6SScott Wood 756d85937e6SScott Wood return dev; 757d85937e6SScott Wood } 758d85937e6SScott Wood 75903f04809SIgor Mammedov static DeviceState *ppce500_init_mpic_kvm(const PPCE500MachineClass *pmc, 7602104d4f5SGreg Kurz IrqLines *irqs, Error **errp) 761d85937e6SScott Wood { 762fe656ebdSMarkus Armbruster Error *err = NULL; 763d85937e6SScott Wood DeviceState *dev; 764d85937e6SScott Wood CPUState *cs; 765d85937e6SScott Wood 766dd49c038SAndreas Färber dev = qdev_create(NULL, TYPE_KVM_OPENPIC); 76703f04809SIgor Mammedov qdev_prop_set_uint32(dev, "model", pmc->mpic_version); 768d85937e6SScott Wood 769fe656ebdSMarkus Armbruster object_property_set_bool(OBJECT(dev), true, "realized", &err); 770fe656ebdSMarkus Armbruster if (err) { 771fe656ebdSMarkus Armbruster error_propagate(errp, err); 772fe656ebdSMarkus Armbruster object_unparent(OBJECT(dev)); 773d85937e6SScott Wood return NULL; 774d85937e6SScott Wood } 775d85937e6SScott Wood 776bdc44640SAndreas Färber CPU_FOREACH(cs) { 777d85937e6SScott Wood if (kvm_openpic_connect_vcpu(dev, cs)) { 778d85937e6SScott Wood fprintf(stderr, "%s: failed to connect vcpu to irqchip\n", 779d85937e6SScott Wood __func__); 780d85937e6SScott Wood abort(); 781d85937e6SScott Wood } 782d85937e6SScott Wood } 783d85937e6SScott Wood 784d85937e6SScott Wood return dev; 785d85937e6SScott Wood } 786d85937e6SScott Wood 78703f04809SIgor Mammedov static DeviceState *ppce500_init_mpic(PPCE500MachineState *pms, 788c91c187fSMichael Davidsaver MemoryRegion *ccsr, 7892104d4f5SGreg Kurz IrqLines *irqs) 790d85937e6SScott Wood { 79103f04809SIgor Mammedov MachineState *machine = MACHINE(pms); 79203f04809SIgor Mammedov const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(pms); 793d85937e6SScott Wood DeviceState *dev = NULL; 794d85937e6SScott Wood SysBusDevice *s; 795d85937e6SScott Wood 796d85937e6SScott Wood if (kvm_enabled()) { 797fe656ebdSMarkus Armbruster Error *err = NULL; 798d85937e6SScott Wood 799446f16a6SMarcel Apfelbaum if (machine_kernel_irqchip_allowed(machine)) { 80003f04809SIgor Mammedov dev = ppce500_init_mpic_kvm(pmc, irqs, &err); 801d85937e6SScott Wood } 802446f16a6SMarcel Apfelbaum if (machine_kernel_irqchip_required(machine) && !dev) { 803c29b77f9SMarkus Armbruster error_reportf_err(err, 804c29b77f9SMarkus Armbruster "kernel_irqchip requested but unavailable: "); 805fe656ebdSMarkus Armbruster exit(1); 806d85937e6SScott Wood } 807d85937e6SScott Wood } 808d85937e6SScott Wood 809d85937e6SScott Wood if (!dev) { 81003f04809SIgor Mammedov dev = ppce500_init_mpic_qemu(pms, irqs); 811d85937e6SScott Wood } 812d85937e6SScott Wood 813d85937e6SScott Wood s = SYS_BUS_DEVICE(dev); 81482fc73b6SScott Wood memory_region_add_subregion(ccsr, MPC8544_MPIC_REGS_OFFSET, 81582fc73b6SScott Wood s->mmio[0].memory); 81682fc73b6SScott Wood 817c91c187fSMichael Davidsaver return dev; 81882fc73b6SScott Wood } 81982fc73b6SScott Wood 820016f7758SAlexander Graf static void ppce500_power_off(void *opaque, int line, int on) 821016f7758SAlexander Graf { 822016f7758SAlexander Graf if (on) { 823cf83f140SEric Blake qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); 824016f7758SAlexander Graf } 825016f7758SAlexander Graf } 826016f7758SAlexander Graf 82703f04809SIgor Mammedov void ppce500_init(MachineState *machine) 8281db09b84Saurel32 { 82939186d8aSRichard Henderson MemoryRegion *address_space_mem = get_system_memory(); 8302646c133SAvi Kivity MemoryRegion *ram = g_new(MemoryRegion, 1); 83103f04809SIgor Mammedov PPCE500MachineState *pms = PPCE500_MACHINE(machine); 83203f04809SIgor Mammedov const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(machine); 8331db09b84Saurel32 PCIBus *pci_bus; 834e2684c0bSAndreas Färber CPUPPCState *env = NULL; 8353812c71fSAlexander Graf uint64_t loadaddr; 8363812c71fSAlexander Graf hwaddr kernel_base = -1LL; 8373812c71fSAlexander Graf int kernel_size = 0; 8383812c71fSAlexander Graf hwaddr dt_base = 0; 8393812c71fSAlexander Graf hwaddr initrd_base = 0; 8403812c71fSAlexander Graf int initrd_size = 0; 8413812c71fSAlexander Graf hwaddr cur_base = 0; 8423812c71fSAlexander Graf char *filename; 8438d622594SDavid Engraf const char *payload_name; 8448d622594SDavid Engraf bool kernel_as_payload; 8453812c71fSAlexander Graf hwaddr bios_entry = 0; 8468d622594SDavid Engraf target_long payload_size; 8473812c71fSAlexander Graf struct boot_info *boot_info; 8483812c71fSAlexander Graf int dt_size; 84982fc73b6SScott Wood int i; 850d575a6ceSBharat Bhushan /* irq num for pin INTA, INTB, INTC and INTD is 1, 2, 3 and 851d575a6ceSBharat Bhushan * 4 respectively */ 852d575a6ceSBharat Bhushan unsigned int pci_irq_nrs[PCI_NUM_PINS] = {1, 2, 3, 4}; 8532104d4f5SGreg Kurz IrqLines *irqs; 854c91c187fSMichael Davidsaver DeviceState *dev, *mpicdev; 855e2684c0bSAndreas Färber CPUPPCState *firstenv = NULL; 8563eddc1beSBharat Bhushan MemoryRegion *ccsr_addr_space; 857dffb1dc2SBharat Bhushan SysBusDevice *s; 8583eddc1beSBharat Bhushan PPCE500CCSRState *ccsr; 8597abb479cSAndrew Randrianasulu I2CBus *i2c; 8601db09b84Saurel32 8612104d4f5SGreg Kurz irqs = g_new0(IrqLines, smp_cpus); 862e61c36d5SAlexander Graf for (i = 0; i < smp_cpus; i++) { 863397b457dSAndreas Färber PowerPCCPU *cpu; 86455e5c285SAndreas Färber CPUState *cs; 865e61c36d5SAlexander Graf qemu_irq *input; 866397b457dSAndreas Färber 86759e816fdSIgor Mammedov cpu = POWERPC_CPU(cpu_create(machine->cpu_type)); 868397b457dSAndreas Färber env = &cpu->env; 86955e5c285SAndreas Färber cs = CPU(cpu); 8701db09b84Saurel32 87100469dc3SValentin Plotkin if (env->mmu_model != POWERPC_MMU_BOOKE206) { 8726f76b817SAlistair Francis error_report("MMU model %i not supported by this machine", 87300469dc3SValentin Plotkin env->mmu_model); 87400469dc3SValentin Plotkin exit(1); 87500469dc3SValentin Plotkin } 87600469dc3SValentin Plotkin 877e61c36d5SAlexander Graf if (!firstenv) { 878e61c36d5SAlexander Graf firstenv = env; 879e61c36d5SAlexander Graf } 880e61c36d5SAlexander Graf 881a915249fSAlexander Graf input = (qemu_irq *)env->irq_inputs; 8822104d4f5SGreg Kurz irqs[i].irq[OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT]; 8832104d4f5SGreg Kurz irqs[i].irq[OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT]; 8846a450df9SAlexander Graf env->spr_cb[SPR_BOOKE_PIR].default_value = cs->cpu_index = i; 88503f04809SIgor Mammedov env->mpic_iack = pmc->ccsrbar_base + MPC8544_MPIC_REGS_OFFSET + 0xa0; 886e61c36d5SAlexander Graf 887a34a92b9SAndreas Färber ppc_booke_timers_init(cpu, 400000000, PPC_TIMER_E500); 8883b989d49SAlexander Graf 8893b989d49SAlexander Graf /* Register reset handler */ 8905c145dacSAlexander Graf if (!i) { 8915c145dacSAlexander Graf /* Primary CPU */ 8925c145dacSAlexander Graf struct boot_info *boot_info; 893e61c36d5SAlexander Graf boot_info = g_malloc0(sizeof(struct boot_info)); 894b3305981SScott Wood qemu_register_reset(ppce500_cpu_reset, cpu); 895e61c36d5SAlexander Graf env->load_info = boot_info; 8965c145dacSAlexander Graf } else { 8975c145dacSAlexander Graf /* Secondary CPUs */ 898b3305981SScott Wood qemu_register_reset(ppce500_cpu_reset_sec, cpu); 8995c145dacSAlexander Graf } 900e61c36d5SAlexander Graf } 901e61c36d5SAlexander Graf 902e61c36d5SAlexander Graf env = firstenv; 9033b989d49SAlexander Graf 9041db09b84Saurel32 /* Fixup Memory size on a alignment boundary */ 9051db09b84Saurel32 ram_size &= ~(RAM_SIZES_ALIGN - 1); 9063ef96221SMarcel Apfelbaum machine->ram_size = ram_size; 9071db09b84Saurel32 9081db09b84Saurel32 /* Register Memory */ 909e938ba0cSShreyas B. Prabhu memory_region_allocate_system_memory(ram, NULL, "mpc8544ds.ram", ram_size); 9102646c133SAvi Kivity memory_region_add_subregion(address_space_mem, 0, ram); 9111db09b84Saurel32 9123eddc1beSBharat Bhushan dev = qdev_create(NULL, "e500-ccsr"); 9133eddc1beSBharat Bhushan object_property_add_child(qdev_get_machine(), "e500-ccsr", 9143eddc1beSBharat Bhushan OBJECT(dev), NULL); 9153eddc1beSBharat Bhushan qdev_init_nofail(dev); 9163eddc1beSBharat Bhushan ccsr = CCSR(dev); 9173eddc1beSBharat Bhushan ccsr_addr_space = &ccsr->ccsr_space; 91803f04809SIgor Mammedov memory_region_add_subregion(address_space_mem, pmc->ccsrbar_base, 9193eddc1beSBharat Bhushan ccsr_addr_space); 920dffb1dc2SBharat Bhushan 92103f04809SIgor Mammedov mpicdev = ppce500_init_mpic(pms, ccsr_addr_space, irqs); 9221db09b84Saurel32 9231db09b84Saurel32 /* Serial */ 9249bca0edbSPeter Maydell if (serial_hd(0)) { 9253eddc1beSBharat Bhushan serial_mm_init(ccsr_addr_space, MPC8544_SERIAL0_REGS_OFFSET, 926c91c187fSMichael Davidsaver 0, qdev_get_gpio_in(mpicdev, 42), 399193, 9279bca0edbSPeter Maydell serial_hd(0), DEVICE_BIG_ENDIAN); 9282d48377aSBlue Swirl } 9291db09b84Saurel32 9309bca0edbSPeter Maydell if (serial_hd(1)) { 9313eddc1beSBharat Bhushan serial_mm_init(ccsr_addr_space, MPC8544_SERIAL1_REGS_OFFSET, 932c91c187fSMichael Davidsaver 0, qdev_get_gpio_in(mpicdev, 42), 399193, 9339bca0edbSPeter Maydell serial_hd(1), DEVICE_BIG_ENDIAN); 9342d48377aSBlue Swirl } 9357abb479cSAndrew Randrianasulu /* I2C */ 9367abb479cSAndrew Randrianasulu dev = qdev_create(NULL, "mpc-i2c"); 9377abb479cSAndrew Randrianasulu s = SYS_BUS_DEVICE(dev); 9387abb479cSAndrew Randrianasulu qdev_init_nofail(dev); 9397abb479cSAndrew Randrianasulu sysbus_connect_irq(s, 0, qdev_get_gpio_in(mpicdev, MPC8544_I2C_IRQ)); 9407abb479cSAndrew Randrianasulu memory_region_add_subregion(ccsr_addr_space, MPC8544_I2C_REGS_OFFSET, 9417abb479cSAndrew Randrianasulu sysbus_mmio_get_region(s, 0)); 9427abb479cSAndrew Randrianasulu i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c"); 9437abb479cSAndrew Randrianasulu i2c_create_slave(i2c, "ds1338", RTC_REGS_OFFSET); 9447abb479cSAndrew Randrianasulu 9451db09b84Saurel32 946b0fb8423SAlexander Graf /* General Utility device */ 947dffb1dc2SBharat Bhushan dev = qdev_create(NULL, "mpc8544-guts"); 948dffb1dc2SBharat Bhushan qdev_init_nofail(dev); 949dffb1dc2SBharat Bhushan s = SYS_BUS_DEVICE(dev); 9503eddc1beSBharat Bhushan memory_region_add_subregion(ccsr_addr_space, MPC8544_UTIL_OFFSET, 951dffb1dc2SBharat Bhushan sysbus_mmio_get_region(s, 0)); 952b0fb8423SAlexander Graf 9531db09b84Saurel32 /* PCI */ 954dffb1dc2SBharat Bhushan dev = qdev_create(NULL, "e500-pcihost"); 955e75ce32aSMichael Davidsaver object_property_add_child(qdev_get_machine(), "pci-host", OBJECT(dev), 956e75ce32aSMichael Davidsaver &error_abort); 95703f04809SIgor Mammedov qdev_prop_set_uint32(dev, "first_slot", pmc->pci_first_slot); 9583016dca0SBharat Bhushan qdev_prop_set_uint32(dev, "first_pin_irq", pci_irq_nrs[0]); 959dffb1dc2SBharat Bhushan qdev_init_nofail(dev); 960dffb1dc2SBharat Bhushan s = SYS_BUS_DEVICE(dev); 961d575a6ceSBharat Bhushan for (i = 0; i < PCI_NUM_PINS; i++) { 962c91c187fSMichael Davidsaver sysbus_connect_irq(s, i, qdev_get_gpio_in(mpicdev, pci_irq_nrs[i])); 963d575a6ceSBharat Bhushan } 964d575a6ceSBharat Bhushan 9653eddc1beSBharat Bhushan memory_region_add_subregion(ccsr_addr_space, MPC8544_PCI_REGS_OFFSET, 966dffb1dc2SBharat Bhushan sysbus_mmio_get_region(s, 0)); 967dffb1dc2SBharat Bhushan 968d461e3b9SAlexander Graf pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0"); 9691db09b84Saurel32 if (!pci_bus) 9701db09b84Saurel32 printf("couldn't create PCI controller!\n"); 9711db09b84Saurel32 9721db09b84Saurel32 if (pci_bus) { 9731db09b84Saurel32 /* Register network interfaces. */ 9741db09b84Saurel32 for (i = 0; i < nb_nics; i++) { 97552310c3fSPaolo Bonzini pci_nic_init_nofail(&nd_table[i], pci_bus, "virtio-net-pci", NULL); 9761db09b84Saurel32 } 9771db09b84Saurel32 } 9781db09b84Saurel32 9795c145dacSAlexander Graf /* Register spinning region */ 98003f04809SIgor Mammedov sysbus_create_simple("e500-spin", pmc->spin_base, NULL); 9815c145dacSAlexander Graf 98203f04809SIgor Mammedov if (pmc->has_mpc8xxx_gpio) { 983016f7758SAlexander Graf qemu_irq poweroff_irq; 984016f7758SAlexander Graf 985b88e77f4SAlexander Graf dev = qdev_create(NULL, "mpc8xxx_gpio"); 986b88e77f4SAlexander Graf s = SYS_BUS_DEVICE(dev); 987b88e77f4SAlexander Graf qdev_init_nofail(dev); 988c91c187fSMichael Davidsaver sysbus_connect_irq(s, 0, qdev_get_gpio_in(mpicdev, MPC8XXX_GPIO_IRQ)); 989b88e77f4SAlexander Graf memory_region_add_subregion(ccsr_addr_space, MPC8XXX_GPIO_OFFSET, 990b88e77f4SAlexander Graf sysbus_mmio_get_region(s, 0)); 991016f7758SAlexander Graf 992016f7758SAlexander Graf /* Power Off GPIO at Pin 0 */ 993016f7758SAlexander Graf poweroff_irq = qemu_allocate_irq(ppce500_power_off, NULL, 0); 994016f7758SAlexander Graf qdev_connect_gpio_out(dev, 0, poweroff_irq); 995b88e77f4SAlexander Graf } 996b88e77f4SAlexander Graf 997f7087343SAlexander Graf /* Platform Bus Device */ 99803f04809SIgor Mammedov if (pmc->has_platform_bus) { 999f7087343SAlexander Graf dev = qdev_create(NULL, TYPE_PLATFORM_BUS_DEVICE); 1000f7087343SAlexander Graf dev->id = TYPE_PLATFORM_BUS_DEVICE; 100103f04809SIgor Mammedov qdev_prop_set_uint32(dev, "num_irqs", pmc->platform_bus_num_irqs); 100203f04809SIgor Mammedov qdev_prop_set_uint32(dev, "mmio_size", pmc->platform_bus_size); 1003f7087343SAlexander Graf qdev_init_nofail(dev); 1004a3fc8396SIgor Mammedov pms->pbus_dev = PLATFORM_BUS_DEVICE(dev); 1005f7087343SAlexander Graf 1006a3fc8396SIgor Mammedov s = SYS_BUS_DEVICE(pms->pbus_dev); 100703f04809SIgor Mammedov for (i = 0; i < pmc->platform_bus_num_irqs; i++) { 100803f04809SIgor Mammedov int irqn = pmc->platform_bus_first_irq + i; 1009c91c187fSMichael Davidsaver sysbus_connect_irq(s, i, qdev_get_gpio_in(mpicdev, irqn)); 1010f7087343SAlexander Graf } 1011f7087343SAlexander Graf 1012f7087343SAlexander Graf memory_region_add_subregion(address_space_mem, 101303f04809SIgor Mammedov pmc->platform_bus_base, 1014f7087343SAlexander Graf sysbus_mmio_get_region(s, 0)); 1015f7087343SAlexander Graf } 1016f7087343SAlexander Graf 10178d622594SDavid Engraf /* 10188d622594SDavid Engraf * Smart firmware defaults ahead! 10198d622594SDavid Engraf * 10208d622594SDavid Engraf * We follow the following table to select which payload we execute. 10218d622594SDavid Engraf * 10228d622594SDavid Engraf * -kernel | -bios | payload 10238d622594SDavid Engraf * ---------+-------+--------- 10248d622594SDavid Engraf * N | Y | u-boot 10258d622594SDavid Engraf * N | N | u-boot 10268d622594SDavid Engraf * Y | Y | u-boot 10278d622594SDavid Engraf * Y | N | kernel 10288d622594SDavid Engraf * 10298d622594SDavid Engraf * This ensures backwards compatibility with how we used to expose 10308d622594SDavid Engraf * -kernel to users but allows them to run through u-boot as well. 10318d622594SDavid Engraf */ 10328d622594SDavid Engraf kernel_as_payload = false; 10338d622594SDavid Engraf if (bios_name == NULL) { 10343ef96221SMarcel Apfelbaum if (machine->kernel_filename) { 10358d622594SDavid Engraf payload_name = machine->kernel_filename; 10368d622594SDavid Engraf kernel_as_payload = true; 10378d622594SDavid Engraf } else { 10388d622594SDavid Engraf payload_name = "u-boot.e500"; 10398d622594SDavid Engraf } 10408d622594SDavid Engraf } else { 10418d622594SDavid Engraf payload_name = bios_name; 10428d622594SDavid Engraf } 10438d622594SDavid Engraf 10448d622594SDavid Engraf filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, payload_name); 10458d622594SDavid Engraf 10464366e1dbSLiam Merwick payload_size = load_elf(filename, NULL, NULL, NULL, 10474366e1dbSLiam Merwick &bios_entry, &loadaddr, NULL, 10488d622594SDavid Engraf 1, PPC_ELF_MACHINE, 0, 0); 10498d622594SDavid Engraf if (payload_size < 0) { 10508d622594SDavid Engraf /* 10518d622594SDavid Engraf * Hrm. No ELF image? Try a uImage, maybe someone is giving us an 10528d622594SDavid Engraf * ePAPR compliant kernel 10538d622594SDavid Engraf */ 1054f831f955SNick Hudson loadaddr = LOAD_UIMAGE_LOADADDR_INVALID; 10558d622594SDavid Engraf payload_size = load_uimage(filename, &bios_entry, &loadaddr, NULL, 10568d622594SDavid Engraf NULL, NULL); 10578d622594SDavid Engraf if (payload_size < 0) { 1058371b74e2SMao Zhongyi error_report("could not load firmware '%s'", filename); 10598d622594SDavid Engraf exit(1); 10608d622594SDavid Engraf } 10618d622594SDavid Engraf } 10628d622594SDavid Engraf 10638d622594SDavid Engraf g_free(filename); 10648d622594SDavid Engraf 10658d622594SDavid Engraf if (kernel_as_payload) { 10668d622594SDavid Engraf kernel_base = loadaddr; 10678d622594SDavid Engraf kernel_size = payload_size; 10688d622594SDavid Engraf } 10698d622594SDavid Engraf 10708d622594SDavid Engraf cur_base = loadaddr + payload_size; 1071ab3dd749SPhilippe Mathieu-Daudé if (cur_base < 32 * MiB) { 1072b4a5f24aSDavid Engraf /* u-boot occupies memory up to 32MB, so load blobs above */ 1073ab3dd749SPhilippe Mathieu-Daudé cur_base = 32 * MiB; 1074b4a5f24aSDavid Engraf } 10758d622594SDavid Engraf 10768d622594SDavid Engraf /* Load bare kernel only if no bios/u-boot has been provided */ 10778d622594SDavid Engraf if (machine->kernel_filename && !kernel_as_payload) { 10783812c71fSAlexander Graf kernel_base = cur_base; 10793812c71fSAlexander Graf kernel_size = load_image_targphys(machine->kernel_filename, 10803812c71fSAlexander Graf cur_base, 10813812c71fSAlexander Graf ram_size - cur_base); 10821db09b84Saurel32 if (kernel_size < 0) { 10836f76b817SAlistair Francis error_report("could not load kernel '%s'", 10843ef96221SMarcel Apfelbaum machine->kernel_filename); 10851db09b84Saurel32 exit(1); 10861db09b84Saurel32 } 1087528e536eSAlexander Graf 10883812c71fSAlexander Graf cur_base += kernel_size; 10891db09b84Saurel32 } 10901db09b84Saurel32 10911db09b84Saurel32 /* Load initrd. */ 10923ef96221SMarcel Apfelbaum if (machine->initrd_filename) { 1093528e536eSAlexander Graf initrd_base = (cur_base + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK; 10943ef96221SMarcel Apfelbaum initrd_size = load_image_targphys(machine->initrd_filename, initrd_base, 1095d7585251Spbrook ram_size - initrd_base); 10961db09b84Saurel32 10971db09b84Saurel32 if (initrd_size < 0) { 10986f76b817SAlistair Francis error_report("could not load initial ram disk '%s'", 10993ef96221SMarcel Apfelbaum machine->initrd_filename); 11001db09b84Saurel32 exit(1); 11011db09b84Saurel32 } 1102528e536eSAlexander Graf 1103528e536eSAlexander Graf cur_base = initrd_base + initrd_size; 11041db09b84Saurel32 } 11051db09b84Saurel32 11063812c71fSAlexander Graf /* 11078d622594SDavid Engraf * Reserve space for dtb behind the kernel image because Linux has a bug 11088d622594SDavid Engraf * where it can only handle the dtb if it's within the first 64MB of where 11098d622594SDavid Engraf * <kernel> starts. dtb cannot not reach initrd_base because INITRD_LOAD_PAD 11108d622594SDavid Engraf * ensures enough space between kernel and initrd. 11113812c71fSAlexander Graf */ 11128d622594SDavid Engraf dt_base = (loadaddr + payload_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK; 11138d622594SDavid Engraf if (dt_base + DTB_MAX_SIZE > ram_size) { 1114371b74e2SMao Zhongyi error_report("not enough memory for device tree"); 11153812c71fSAlexander Graf exit(1); 11163812c71fSAlexander Graf } 11175c145dacSAlexander Graf 111803f04809SIgor Mammedov dt_size = ppce500_prep_device_tree(pms, dt_base, 1119903585deSAlexander Graf initrd_base, initrd_size, 11203812c71fSAlexander Graf kernel_base, kernel_size); 1121cba2026aSAlexander Graf if (dt_size < 0) { 11226f76b817SAlistair Francis error_report("couldn't load device tree"); 11231db09b84Saurel32 exit(1); 11241db09b84Saurel32 } 1125b8dec144SAlexander Graf assert(dt_size < DTB_MAX_SIZE); 11261db09b84Saurel32 1127e61c36d5SAlexander Graf boot_info = env->load_info; 11283812c71fSAlexander Graf boot_info->entry = bios_entry; 11293b989d49SAlexander Graf boot_info->dt_base = dt_base; 1130cba2026aSAlexander Graf boot_info->dt_size = dt_size; 11311db09b84Saurel32 } 11323eddc1beSBharat Bhushan 1133d0c2b0d0Sxiaoqiang zhao static void e500_ccsr_initfn(Object *obj) 11343eddc1beSBharat Bhushan { 1135d0c2b0d0Sxiaoqiang zhao PPCE500CCSRState *ccsr = CCSR(obj); 1136d0c2b0d0Sxiaoqiang zhao memory_region_init(&ccsr->ccsr_space, obj, "e500-ccsr", 11373eddc1beSBharat Bhushan MPC8544_CCSRBAR_SIZE); 11383eddc1beSBharat Bhushan } 11393eddc1beSBharat Bhushan 11403eddc1beSBharat Bhushan static const TypeInfo e500_ccsr_info = { 11413eddc1beSBharat Bhushan .name = TYPE_CCSR, 11423eddc1beSBharat Bhushan .parent = TYPE_SYS_BUS_DEVICE, 11433eddc1beSBharat Bhushan .instance_size = sizeof(PPCE500CCSRState), 1144d0c2b0d0Sxiaoqiang zhao .instance_init = e500_ccsr_initfn, 11453eddc1beSBharat Bhushan }; 11463eddc1beSBharat Bhushan 114703f04809SIgor Mammedov static const TypeInfo ppce500_info = { 114803f04809SIgor Mammedov .name = TYPE_PPCE500_MACHINE, 114903f04809SIgor Mammedov .parent = TYPE_MACHINE, 115003f04809SIgor Mammedov .abstract = true, 1151a3fc8396SIgor Mammedov .instance_size = sizeof(PPCE500MachineState), 115203f04809SIgor Mammedov .class_size = sizeof(PPCE500MachineClass), 115303f04809SIgor Mammedov }; 115403f04809SIgor Mammedov 11553eddc1beSBharat Bhushan static void e500_register_types(void) 11563eddc1beSBharat Bhushan { 11573eddc1beSBharat Bhushan type_register_static(&e500_ccsr_info); 115803f04809SIgor Mammedov type_register_static(&ppce500_info); 11593eddc1beSBharat Bhushan } 11603eddc1beSBharat Bhushan 11613eddc1beSBharat Bhushan type_init(e500_register_types) 1162