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" 18a8d25326SMarkus 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" 250d09e41aSPaolo Bonzini #include "hw/char/serial.h" 26a2cb15b0SMichael S. Tsirkin #include "hw/pci/pci.h" 274a18e7c9SScott Wood #include "hw/boards.h" 289c17d615SPaolo Bonzini #include "sysemu/sysemu.h" 299c17d615SPaolo Bonzini #include "sysemu/kvm.h" 3071e8a915SMarkus Armbruster #include "sysemu/reset.h" 3154d31236SMarkus Armbruster #include "sysemu/runstate.h" 321db09b84Saurel32 #include "kvm_ppc.h" 339c17d615SPaolo Bonzini #include "sysemu/device_tree.h" 340d09e41aSPaolo Bonzini #include "hw/ppc/openpic.h" 358d085cf0SMark Cave-Ayland #include "hw/ppc/openpic_kvm.h" 360d09e41aSPaolo Bonzini #include "hw/ppc/ppc.h" 37a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h" 384a18e7c9SScott Wood #include "hw/loader.h" 39ca20cf32SBlue Swirl #include "elf.h" 404a18e7c9SScott Wood #include "hw/sysbus.h" 41022c62cbSPaolo Bonzini #include "exec/address-spaces.h" 421de7afc9SPaolo Bonzini #include "qemu/host-utils.h" 43922a01a0SMarkus Armbruster #include "qemu/option.h" 440d09e41aSPaolo Bonzini #include "hw/pci-host/ppce500.h" 45f7087343SAlexander Graf #include "qemu/error-report.h" 46f7087343SAlexander Graf #include "hw/platform-bus.h" 47fdfb7f2cSAlexander Graf #include "hw/net/fsl_etsec/etsec.h" 487abb479cSAndrew Randrianasulu #include "hw/i2c/i2c.h" 4964552b6bSMarkus Armbruster #include "hw/irq.h" 501db09b84Saurel32 51cefd3cdbSBharat Bhushan #define EPAPR_MAGIC (0x45504150) 521db09b84Saurel32 #define BINARY_DEVICE_TREE_FILE "mpc8544ds.dtb" 539dd5eba1SScott Wood #define DTC_LOAD_PAD 0x1800000 5475bb6589SLiu Yu #define DTC_PAD_MASK 0xFFFFF 55ab3dd749SPhilippe Mathieu-Daudé #define DTB_MAX_SIZE (8 * MiB) 5675bb6589SLiu Yu #define INITRD_LOAD_PAD 0x2000000 5775bb6589SLiu Yu #define INITRD_PAD_MASK 0xFFFFFF 581db09b84Saurel32 59ab3dd749SPhilippe Mathieu-Daudé #define RAM_SIZES_ALIGN (64 * MiB) 601db09b84Saurel32 61b3305981SScott Wood /* TODO: parameterize */ 62ed2bc496SAlexander Graf #define MPC8544_CCSRBAR_SIZE 0x00100000ULL 63dffb1dc2SBharat Bhushan #define MPC8544_MPIC_REGS_OFFSET 0x40000ULL 64a911b7a9SAlexander Graf #define MPC8544_MSI_REGS_OFFSET 0x41600ULL 65dffb1dc2SBharat Bhushan #define MPC8544_SERIAL0_REGS_OFFSET 0x4500ULL 66dffb1dc2SBharat Bhushan #define MPC8544_SERIAL1_REGS_OFFSET 0x4600ULL 67dffb1dc2SBharat Bhushan #define MPC8544_PCI_REGS_OFFSET 0x8000ULL 68ed2bc496SAlexander Graf #define MPC8544_PCI_REGS_SIZE 0x1000ULL 69dffb1dc2SBharat Bhushan #define MPC8544_UTIL_OFFSET 0xe0000ULL 70b88e77f4SAlexander Graf #define MPC8XXX_GPIO_OFFSET 0x000FF000ULL 717abb479cSAndrew Randrianasulu #define MPC8544_I2C_REGS_OFFSET 0x3000ULL 7282e345f5SAmit Tomar #define MPC8XXX_GPIO_IRQ 47 737abb479cSAndrew Randrianasulu #define MPC8544_I2C_IRQ 43 747abb479cSAndrew Randrianasulu #define RTC_REGS_OFFSET 0x68 751db09b84Saurel32 763b989d49SAlexander Graf struct boot_info 773b989d49SAlexander Graf { 783b989d49SAlexander Graf uint32_t dt_base; 79cba2026aSAlexander Graf uint32_t dt_size; 803b989d49SAlexander Graf uint32_t entry; 813b989d49SAlexander Graf }; 823b989d49SAlexander Graf 83347dd79dSAlexander Graf static uint32_t *pci_map_create(void *fdt, uint32_t mpic, int first_slot, 84347dd79dSAlexander Graf int nr_slots, int *len) 850dbc0798SAlexander Graf { 86347dd79dSAlexander Graf int i = 0; 87347dd79dSAlexander Graf int slot; 88347dd79dSAlexander Graf int pci_irq; 899e2c1298SAlexander Graf int host_irq; 90347dd79dSAlexander Graf int last_slot = first_slot + nr_slots; 91347dd79dSAlexander Graf uint32_t *pci_map; 920dbc0798SAlexander Graf 93347dd79dSAlexander Graf *len = nr_slots * 4 * 7 * sizeof(uint32_t); 94347dd79dSAlexander Graf pci_map = g_malloc(*len); 95347dd79dSAlexander Graf 96347dd79dSAlexander Graf for (slot = first_slot; slot < last_slot; slot++) { 97347dd79dSAlexander Graf for (pci_irq = 0; pci_irq < 4; pci_irq++) { 98347dd79dSAlexander Graf pci_map[i++] = cpu_to_be32(slot << 11); 99347dd79dSAlexander Graf pci_map[i++] = cpu_to_be32(0x0); 100347dd79dSAlexander Graf pci_map[i++] = cpu_to_be32(0x0); 101347dd79dSAlexander Graf pci_map[i++] = cpu_to_be32(pci_irq + 1); 102347dd79dSAlexander Graf pci_map[i++] = cpu_to_be32(mpic); 1039e2c1298SAlexander Graf host_irq = ppce500_pci_map_irq_slot(slot, pci_irq); 1049e2c1298SAlexander Graf pci_map[i++] = cpu_to_be32(host_irq + 1); 105347dd79dSAlexander Graf pci_map[i++] = cpu_to_be32(0x1); 1060dbc0798SAlexander Graf } 1070dbc0798SAlexander Graf } 1080dbc0798SAlexander Graf 109347dd79dSAlexander Graf assert((i * sizeof(uint32_t)) == *len); 110347dd79dSAlexander Graf 111347dd79dSAlexander Graf return pci_map; 112347dd79dSAlexander Graf } 113347dd79dSAlexander Graf 114a053a7ceSAlexander Graf static void dt_serial_create(void *fdt, unsigned long long offset, 115a053a7ceSAlexander Graf const char *soc, const char *mpic, 116a053a7ceSAlexander Graf const char *alias, int idx, bool defcon) 117a053a7ceSAlexander Graf { 1182fb513d3SGreg Kurz char *ser; 119a053a7ceSAlexander Graf 1202fb513d3SGreg Kurz ser = g_strdup_printf("%s/serial@%llx", soc, offset); 1215a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, ser); 1225a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, ser, "device_type", "serial"); 1235a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, ser, "compatible", "ns16550"); 1245a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, ser, "reg", offset, 0x100); 1255a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, ser, "cell-index", idx); 1265a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, ser, "clock-frequency", 0); 1275a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, ser, "interrupts", 42, 2); 1285a4348d1SPeter Crosthwaite qemu_fdt_setprop_phandle(fdt, ser, "interrupt-parent", mpic); 1295a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, "/aliases", alias, ser); 130a053a7ceSAlexander Graf 131a053a7ceSAlexander Graf if (defcon) { 13290ee4e01SNikunj A Dadhania /* 13390ee4e01SNikunj A Dadhania * "linux,stdout-path" and "stdout" properties are deprecated by linux 13490ee4e01SNikunj A Dadhania * kernel. New platforms should only use the "stdout-path" property. Set 13590ee4e01SNikunj A Dadhania * the new property and continue using older property to remain 13690ee4e01SNikunj A Dadhania * compatible with the existing firmware. 13790ee4e01SNikunj A Dadhania */ 1385a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, "/chosen", "linux,stdout-path", ser); 13990ee4e01SNikunj A Dadhania qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", ser); 140a053a7ceSAlexander Graf } 1412fb513d3SGreg Kurz g_free(ser); 142a053a7ceSAlexander Graf } 143a053a7ceSAlexander Graf 144b88e77f4SAlexander Graf static void create_dt_mpc8xxx_gpio(void *fdt, const char *soc, const char *mpic) 145b88e77f4SAlexander Graf { 146b88e77f4SAlexander Graf hwaddr mmio0 = MPC8XXX_GPIO_OFFSET; 147b88e77f4SAlexander Graf int irq0 = MPC8XXX_GPIO_IRQ; 148b88e77f4SAlexander Graf gchar *node = g_strdup_printf("%s/gpio@%"PRIx64, soc, mmio0); 149016f7758SAlexander Graf gchar *poweroff = g_strdup_printf("%s/power-off", soc); 150016f7758SAlexander Graf int gpio_ph; 151b88e77f4SAlexander Graf 152b88e77f4SAlexander Graf qemu_fdt_add_subnode(fdt, node); 153b88e77f4SAlexander Graf qemu_fdt_setprop_string(fdt, node, "compatible", "fsl,qoriq-gpio"); 154b88e77f4SAlexander Graf qemu_fdt_setprop_cells(fdt, node, "reg", mmio0, 0x1000); 155b88e77f4SAlexander Graf qemu_fdt_setprop_cells(fdt, node, "interrupts", irq0, 0x2); 156b88e77f4SAlexander Graf qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", mpic); 157b88e77f4SAlexander Graf qemu_fdt_setprop_cells(fdt, node, "#gpio-cells", 2); 158b88e77f4SAlexander Graf qemu_fdt_setprop(fdt, node, "gpio-controller", NULL, 0); 159016f7758SAlexander Graf gpio_ph = qemu_fdt_alloc_phandle(fdt); 160016f7758SAlexander Graf qemu_fdt_setprop_cell(fdt, node, "phandle", gpio_ph); 161016f7758SAlexander Graf qemu_fdt_setprop_cell(fdt, node, "linux,phandle", gpio_ph); 162016f7758SAlexander Graf 163016f7758SAlexander Graf /* Power Off Pin */ 164016f7758SAlexander Graf qemu_fdt_add_subnode(fdt, poweroff); 165016f7758SAlexander Graf qemu_fdt_setprop_string(fdt, poweroff, "compatible", "gpio-poweroff"); 166016f7758SAlexander Graf qemu_fdt_setprop_cells(fdt, poweroff, "gpios", gpio_ph, 0, 0); 167b88e77f4SAlexander Graf 168b88e77f4SAlexander Graf g_free(node); 169016f7758SAlexander Graf g_free(poweroff); 170b88e77f4SAlexander Graf } 171b88e77f4SAlexander Graf 1727abb479cSAndrew Randrianasulu static void dt_rtc_create(void *fdt, const char *i2c, const char *alias) 1737abb479cSAndrew Randrianasulu { 1747abb479cSAndrew Randrianasulu int offset = RTC_REGS_OFFSET; 1757abb479cSAndrew Randrianasulu 1767abb479cSAndrew Randrianasulu gchar *rtc = g_strdup_printf("%s/rtc@%"PRIx32, i2c, offset); 1777abb479cSAndrew Randrianasulu qemu_fdt_add_subnode(fdt, rtc); 1787abb479cSAndrew Randrianasulu qemu_fdt_setprop_string(fdt, rtc, "compatible", "pericom,pt7c4338"); 1797abb479cSAndrew Randrianasulu qemu_fdt_setprop_cells(fdt, rtc, "reg", offset); 1807abb479cSAndrew Randrianasulu qemu_fdt_setprop_string(fdt, "/aliases", alias, rtc); 1817abb479cSAndrew Randrianasulu 1827abb479cSAndrew Randrianasulu g_free(rtc); 1837abb479cSAndrew Randrianasulu } 1847abb479cSAndrew Randrianasulu 1857abb479cSAndrew Randrianasulu static void dt_i2c_create(void *fdt, const char *soc, const char *mpic, 1867abb479cSAndrew Randrianasulu const char *alias) 1877abb479cSAndrew Randrianasulu { 1887abb479cSAndrew Randrianasulu hwaddr mmio0 = MPC8544_I2C_REGS_OFFSET; 1897abb479cSAndrew Randrianasulu int irq0 = MPC8544_I2C_IRQ; 1907abb479cSAndrew Randrianasulu 1917abb479cSAndrew Randrianasulu gchar *i2c = g_strdup_printf("%s/i2c@%"PRIx64, soc, mmio0); 1927abb479cSAndrew Randrianasulu qemu_fdt_add_subnode(fdt, i2c); 1937abb479cSAndrew Randrianasulu qemu_fdt_setprop_string(fdt, i2c, "device_type", "i2c"); 1947abb479cSAndrew Randrianasulu qemu_fdt_setprop_string(fdt, i2c, "compatible", "fsl-i2c"); 1957abb479cSAndrew Randrianasulu qemu_fdt_setprop_cells(fdt, i2c, "reg", mmio0, 0x14); 1967abb479cSAndrew Randrianasulu qemu_fdt_setprop_cells(fdt, i2c, "cell-index", 0); 1977abb479cSAndrew Randrianasulu qemu_fdt_setprop_cells(fdt, i2c, "interrupts", irq0, 0x2); 1987abb479cSAndrew Randrianasulu qemu_fdt_setprop_phandle(fdt, i2c, "interrupt-parent", mpic); 1997abb479cSAndrew Randrianasulu qemu_fdt_setprop_string(fdt, "/aliases", alias, i2c); 2007abb479cSAndrew Randrianasulu 2017abb479cSAndrew Randrianasulu g_free(i2c); 2027abb479cSAndrew Randrianasulu } 2037abb479cSAndrew Randrianasulu 2047abb479cSAndrew Randrianasulu 205f7087343SAlexander Graf typedef struct PlatformDevtreeData { 206f7087343SAlexander Graf void *fdt; 207f7087343SAlexander Graf const char *mpic; 208f7087343SAlexander Graf int irq_start; 209f7087343SAlexander Graf const char *node; 210f7087343SAlexander Graf PlatformBusDevice *pbus; 211f7087343SAlexander Graf } PlatformDevtreeData; 212f7087343SAlexander Graf 213fdfb7f2cSAlexander Graf static int create_devtree_etsec(SysBusDevice *sbdev, PlatformDevtreeData *data) 214fdfb7f2cSAlexander Graf { 215fdfb7f2cSAlexander Graf eTSEC *etsec = ETSEC_COMMON(sbdev); 216fdfb7f2cSAlexander Graf PlatformBusDevice *pbus = data->pbus; 217fdfb7f2cSAlexander Graf hwaddr mmio0 = platform_bus_get_mmio_addr(pbus, sbdev, 0); 218fdfb7f2cSAlexander Graf int irq0 = platform_bus_get_irqn(pbus, sbdev, 0); 219fdfb7f2cSAlexander Graf int irq1 = platform_bus_get_irqn(pbus, sbdev, 1); 220fdfb7f2cSAlexander Graf int irq2 = platform_bus_get_irqn(pbus, sbdev, 2); 221fdfb7f2cSAlexander Graf gchar *node = g_strdup_printf("/platform/ethernet@%"PRIx64, mmio0); 222fdfb7f2cSAlexander Graf gchar *group = g_strdup_printf("%s/queue-group", node); 223fdfb7f2cSAlexander Graf void *fdt = data->fdt; 224fdfb7f2cSAlexander Graf 225fdfb7f2cSAlexander Graf assert((int64_t)mmio0 >= 0); 226fdfb7f2cSAlexander Graf assert(irq0 >= 0); 227fdfb7f2cSAlexander Graf assert(irq1 >= 0); 228fdfb7f2cSAlexander Graf assert(irq2 >= 0); 229fdfb7f2cSAlexander Graf 230fdfb7f2cSAlexander Graf qemu_fdt_add_subnode(fdt, node); 231fdfb7f2cSAlexander Graf qemu_fdt_setprop_string(fdt, node, "device_type", "network"); 232fdfb7f2cSAlexander Graf qemu_fdt_setprop_string(fdt, node, "compatible", "fsl,etsec2"); 233fdfb7f2cSAlexander Graf qemu_fdt_setprop_string(fdt, node, "model", "eTSEC"); 234fdfb7f2cSAlexander Graf qemu_fdt_setprop(fdt, node, "local-mac-address", etsec->conf.macaddr.a, 6); 235fdfb7f2cSAlexander Graf qemu_fdt_setprop_cells(fdt, node, "fixed-link", 0, 1, 1000, 0, 0); 236fdfb7f2cSAlexander Graf 237fdfb7f2cSAlexander Graf qemu_fdt_add_subnode(fdt, group); 238fdfb7f2cSAlexander Graf qemu_fdt_setprop_cells(fdt, group, "reg", mmio0, 0x1000); 239fdfb7f2cSAlexander Graf qemu_fdt_setprop_cells(fdt, group, "interrupts", 240fdfb7f2cSAlexander Graf data->irq_start + irq0, 0x2, 241fdfb7f2cSAlexander Graf data->irq_start + irq1, 0x2, 242fdfb7f2cSAlexander Graf data->irq_start + irq2, 0x2); 243fdfb7f2cSAlexander Graf 244fdfb7f2cSAlexander Graf g_free(node); 245fdfb7f2cSAlexander Graf g_free(group); 246fdfb7f2cSAlexander Graf 247fdfb7f2cSAlexander Graf return 0; 248fdfb7f2cSAlexander Graf } 249fdfb7f2cSAlexander Graf 2504f01a637SDavid Gibson static void sysbus_device_create_devtree(SysBusDevice *sbdev, void *opaque) 251f7087343SAlexander Graf { 252f7087343SAlexander Graf PlatformDevtreeData *data = opaque; 253f7087343SAlexander Graf bool matched = false; 254f7087343SAlexander Graf 255fdfb7f2cSAlexander Graf if (object_dynamic_cast(OBJECT(sbdev), TYPE_ETSEC_COMMON)) { 256fdfb7f2cSAlexander Graf create_devtree_etsec(sbdev, data); 257fdfb7f2cSAlexander Graf matched = true; 258fdfb7f2cSAlexander Graf } 259fdfb7f2cSAlexander Graf 260f7087343SAlexander Graf if (!matched) { 261f7087343SAlexander Graf error_report("Device %s is not supported by this machine yet.", 262f7087343SAlexander Graf qdev_fw_name(DEVICE(sbdev))); 263f7087343SAlexander Graf exit(1); 264f7087343SAlexander Graf } 265f7087343SAlexander Graf } 266f7087343SAlexander Graf 267a3fc8396SIgor Mammedov static void platform_bus_create_devtree(PPCE500MachineState *pms, 26803f04809SIgor Mammedov void *fdt, const char *mpic) 269f7087343SAlexander Graf { 270a3fc8396SIgor Mammedov const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(pms); 27103f04809SIgor Mammedov gchar *node = g_strdup_printf("/platform@%"PRIx64, pmc->platform_bus_base); 272f7087343SAlexander Graf const char platcomp[] = "qemu,platform\0simple-bus"; 27303f04809SIgor Mammedov uint64_t addr = pmc->platform_bus_base; 27403f04809SIgor Mammedov uint64_t size = pmc->platform_bus_size; 27503f04809SIgor Mammedov int irq_start = pmc->platform_bus_first_irq; 276f7087343SAlexander Graf 277f7087343SAlexander Graf /* Create a /platform node that we can put all devices into */ 278f7087343SAlexander Graf 279f7087343SAlexander Graf qemu_fdt_add_subnode(fdt, node); 280f7087343SAlexander Graf qemu_fdt_setprop(fdt, node, "compatible", platcomp, sizeof(platcomp)); 281f7087343SAlexander Graf 282f7087343SAlexander Graf /* Our platform bus region is less than 32bit big, so 1 cell is enough for 283f7087343SAlexander Graf address and size */ 284f7087343SAlexander Graf qemu_fdt_setprop_cells(fdt, node, "#size-cells", 1); 285f7087343SAlexander Graf qemu_fdt_setprop_cells(fdt, node, "#address-cells", 1); 286f7087343SAlexander Graf qemu_fdt_setprop_cells(fdt, node, "ranges", 0, addr >> 32, addr, size); 287f7087343SAlexander Graf 288f7087343SAlexander Graf qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", mpic); 289f7087343SAlexander Graf 290a3fc8396SIgor Mammedov /* Create dt nodes for dynamic devices */ 291f7087343SAlexander Graf PlatformDevtreeData data = { 292f7087343SAlexander Graf .fdt = fdt, 293f7087343SAlexander Graf .mpic = mpic, 294f7087343SAlexander Graf .irq_start = irq_start, 295f7087343SAlexander Graf .node = node, 296a3fc8396SIgor Mammedov .pbus = pms->pbus_dev, 297f7087343SAlexander Graf }; 298f7087343SAlexander Graf 299f7087343SAlexander Graf /* Loop through all dynamic sysbus devices and create nodes for them */ 300f7087343SAlexander Graf foreach_dynamic_sysbus_device(sysbus_device_create_devtree, &data); 301f7087343SAlexander Graf 302f7087343SAlexander Graf g_free(node); 303f7087343SAlexander Graf } 304f7087343SAlexander Graf 30503f04809SIgor Mammedov static int ppce500_load_device_tree(PPCE500MachineState *pms, 306a8170e5eSAvi Kivity hwaddr addr, 307a8170e5eSAvi Kivity hwaddr initrd_base, 30828290f37SAlexander Graf hwaddr initrd_size, 309903585deSAlexander Graf hwaddr kernel_base, 310903585deSAlexander Graf hwaddr kernel_size, 31128290f37SAlexander Graf bool dry_run) 3121db09b84Saurel32 { 31303f04809SIgor Mammedov MachineState *machine = MACHINE(pms); 314fe6b6346SLike Xu unsigned int smp_cpus = machine->smp.cpus; 31503f04809SIgor Mammedov const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(pms); 31628290f37SAlexander Graf CPUPPCState *env = first_cpu->env_ptr; 317dbf916d8SAurelien Jarno int ret = -1; 3183ef96221SMarcel Apfelbaum uint64_t mem_reg_property[] = { 0, cpu_to_be64(machine->ram_size) }; 3197ec632b4Spbrook int fdt_size; 320dbf916d8SAurelien Jarno void *fdt; 3215de6b46dSAlexander Graf uint8_t hypercall[16]; 322911d6e7aSAlexander Graf uint32_t clock_freq = 400000000; 323911d6e7aSAlexander Graf uint32_t tb_freq = 400000000; 324621d05e3SAlexander Graf int i; 325ebb9518aSAlexander Graf char compatible_sb[] = "fsl,mpc8544-immr\0simple-bus"; 3262fb513d3SGreg Kurz char *soc; 3272fb513d3SGreg Kurz char *mpic; 32819ac9deaSAlexander Graf uint32_t mpic_ph; 329a911b7a9SAlexander Graf uint32_t msi_ph; 3302fb513d3SGreg Kurz char *gutil; 3312fb513d3SGreg Kurz char *pci; 3322fb513d3SGreg Kurz char *msi; 333347dd79dSAlexander Graf uint32_t *pci_map = NULL; 334347dd79dSAlexander Graf int len; 3353627757eSAlexander Graf uint32_t pci_ranges[14] = 3363627757eSAlexander Graf { 33703f04809SIgor Mammedov 0x2000000, 0x0, pmc->pci_mmio_bus_base, 33803f04809SIgor Mammedov pmc->pci_mmio_base >> 32, pmc->pci_mmio_base, 3393627757eSAlexander Graf 0x0, 0x20000000, 3403627757eSAlexander Graf 3413627757eSAlexander Graf 0x1000000, 0x0, 0x0, 34203f04809SIgor Mammedov pmc->pci_pio_base >> 32, pmc->pci_pio_base, 3433627757eSAlexander Graf 0x0, 0x10000, 3443627757eSAlexander Graf }; 3452ff3de68SMarkus Armbruster QemuOpts *machine_opts = qemu_get_machine_opts(); 3462ff3de68SMarkus Armbruster const char *dtb_file = qemu_opt_get(machine_opts, "dtb"); 3472ff3de68SMarkus Armbruster const char *toplevel_compat = qemu_opt_get(machine_opts, "dt_compatible"); 348d1b93565SAlexander Graf 349d1b93565SAlexander Graf if (dtb_file) { 350d1b93565SAlexander Graf char *filename; 351d1b93565SAlexander Graf filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_file); 352d1b93565SAlexander Graf if (!filename) { 353d1b93565SAlexander Graf goto out; 354d1b93565SAlexander Graf } 355d1b93565SAlexander Graf 356d1b93565SAlexander Graf fdt = load_device_tree(filename, &fdt_size); 3572343dd11SMichael Tokarev g_free(filename); 358d1b93565SAlexander Graf if (!fdt) { 359d1b93565SAlexander Graf goto out; 360d1b93565SAlexander Graf } 361d1b93565SAlexander Graf goto done; 362d1b93565SAlexander Graf } 3631db09b84Saurel32 3642636fcb6SAlexander Graf fdt = create_device_tree(&fdt_size); 3655cea8590SPaul Brook if (fdt == NULL) { 3665cea8590SPaul Brook goto out; 3675cea8590SPaul Brook } 3681db09b84Saurel32 3691db09b84Saurel32 /* Manipulate device tree in memory. */ 3705a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 2); 3715a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 2); 37251b852b7SAlexander Graf 3735a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, "/memory"); 3745a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, "/memory", "device_type", "memory"); 3755a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, "/memory", "reg", mem_reg_property, 3761db09b84Saurel32 sizeof(mem_reg_property)); 3771db09b84Saurel32 3785a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, "/chosen"); 3793b989d49SAlexander Graf if (initrd_size) { 3805a4348d1SPeter Crosthwaite ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start", 3811db09b84Saurel32 initrd_base); 3823b989d49SAlexander Graf if (ret < 0) { 3831db09b84Saurel32 fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n"); 3843b989d49SAlexander Graf } 3851db09b84Saurel32 3865a4348d1SPeter Crosthwaite ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end", 3871db09b84Saurel32 (initrd_base + initrd_size)); 3883b989d49SAlexander Graf if (ret < 0) { 3891db09b84Saurel32 fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n"); 3903b989d49SAlexander Graf } 391903585deSAlexander Graf 392903585deSAlexander Graf } 393903585deSAlexander Graf 394903585deSAlexander Graf if (kernel_base != -1ULL) { 395903585deSAlexander Graf qemu_fdt_setprop_cells(fdt, "/chosen", "qemu,boot-kernel", 396903585deSAlexander Graf kernel_base >> 32, kernel_base, 397903585deSAlexander Graf kernel_size >> 32, kernel_size); 3983b989d49SAlexander Graf } 3991db09b84Saurel32 4005a4348d1SPeter Crosthwaite ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", 4013ef96221SMarcel Apfelbaum machine->kernel_cmdline); 4021db09b84Saurel32 if (ret < 0) 4031db09b84Saurel32 fprintf(stderr, "couldn't set /chosen/bootargs\n"); 4041db09b84Saurel32 4051db09b84Saurel32 if (kvm_enabled()) { 406911d6e7aSAlexander Graf /* Read out host's frequencies */ 407911d6e7aSAlexander Graf clock_freq = kvmppc_get_clockfreq(); 408911d6e7aSAlexander Graf tb_freq = kvmppc_get_tbfreq(); 4095de6b46dSAlexander Graf 4105de6b46dSAlexander Graf /* indicate KVM hypercall interface */ 4115a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, "/hypervisor"); 4125a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, "/hypervisor", "compatible", 4135de6b46dSAlexander Graf "linux,kvm"); 4145de6b46dSAlexander Graf kvmppc_get_hypercall(env, hypercall, sizeof(hypercall)); 4155a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, "/hypervisor", "hcall-instructions", 4165de6b46dSAlexander Graf hypercall, sizeof(hypercall)); 4171a61a9aeSStuart Yoder /* if KVM supports the idle hcall, set property indicating this */ 4181a61a9aeSStuart Yoder if (kvmppc_get_hasidle(env)) { 4195a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, "/hypervisor", "has-idle", NULL, 0); 4201a61a9aeSStuart Yoder } 4211db09b84Saurel32 } 4221db09b84Saurel32 423625e665bSAlexander Graf /* Create CPU nodes */ 4245a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, "/cpus"); 4255a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 1); 4265a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0); 427625e665bSAlexander Graf 4281e3debf0SAlexander Graf /* We need to generate the cpu nodes in reverse order, so Linux can pick 4291e3debf0SAlexander Graf the first node as boot node and be happy */ 4301e3debf0SAlexander Graf for (i = smp_cpus - 1; i >= 0; i--) { 431440c8152SAndreas Färber CPUState *cpu; 4322fb513d3SGreg Kurz char *cpu_name; 43303f04809SIgor Mammedov uint64_t cpu_release_addr = pmc->spin_base + (i * 0x20); 43410f25a46SAlexander Graf 435440c8152SAndreas Färber cpu = qemu_get_cpu(i); 43655e5c285SAndreas Färber if (cpu == NULL) { 4371e3debf0SAlexander Graf continue; 4381e3debf0SAlexander Graf } 439440c8152SAndreas Färber env = cpu->env_ptr; 4401e3debf0SAlexander Graf 4412fb513d3SGreg Kurz cpu_name = g_strdup_printf("/cpus/PowerPC,8544@%x", i); 4425a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, cpu_name); 4435a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq); 4445a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq); 4455a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, cpu_name, "device_type", "cpu"); 4466d536570SSam Bobroff qemu_fdt_setprop_cell(fdt, cpu_name, "reg", i); 4475a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-line-size", 4481e3debf0SAlexander Graf env->dcache_line_size); 4495a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-line-size", 4501e3debf0SAlexander Graf env->icache_line_size); 4515a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-size", 0x8000); 4525a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-size", 0x8000); 4535a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "bus-frequency", 0); 45455e5c285SAndreas Färber if (cpu->cpu_index) { 4555a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, cpu_name, "status", "disabled"); 4565a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, cpu_name, "enable-method", 4575a4348d1SPeter Crosthwaite "spin-table"); 4585a4348d1SPeter Crosthwaite qemu_fdt_setprop_u64(fdt, cpu_name, "cpu-release-addr", 4591d2e5c52SAlexander Graf cpu_release_addr); 4601e3debf0SAlexander Graf } else { 4615a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, cpu_name, "status", "okay"); 4621e3debf0SAlexander Graf } 4632fb513d3SGreg Kurz g_free(cpu_name); 4641db09b84Saurel32 } 4651db09b84Saurel32 4665a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, "/aliases"); 4675da96624SAlexander Graf /* XXX These should go into their respective devices' code */ 4682fb513d3SGreg Kurz soc = g_strdup_printf("/soc@%"PRIx64, pmc->ccsrbar_base); 4695a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, soc); 4705a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, soc, "device_type", "soc"); 4715a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, soc, "compatible", compatible_sb, 472ebb9518aSAlexander Graf sizeof(compatible_sb)); 4735a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, soc, "#address-cells", 1); 4745a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, soc, "#size-cells", 1); 4755a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, soc, "ranges", 0x0, 47603f04809SIgor Mammedov pmc->ccsrbar_base >> 32, pmc->ccsrbar_base, 4775da96624SAlexander Graf MPC8544_CCSRBAR_SIZE); 4785da96624SAlexander Graf /* XXX should contain a reasonable value */ 4795a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, soc, "bus-frequency", 0); 4805da96624SAlexander Graf 4812fb513d3SGreg Kurz mpic = g_strdup_printf("%s/pic@%llx", soc, MPC8544_MPIC_REGS_OFFSET); 4825a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, mpic); 4835a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, mpic, "device_type", "open-pic"); 4845a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, mpic, "compatible", "fsl,mpic"); 4855a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_OFFSET, 486dffb1dc2SBharat Bhushan 0x40000); 4875a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, mpic, "#address-cells", 0); 4885a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, mpic, "#interrupt-cells", 2); 4895a4348d1SPeter Crosthwaite mpic_ph = qemu_fdt_alloc_phandle(fdt); 4905a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, mpic, "phandle", mpic_ph); 4915a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, mpic, "linux,phandle", mpic_ph); 4925a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, mpic, "interrupt-controller", NULL, 0); 49319ac9deaSAlexander Graf 4940cfc6e8dSAlexander Graf /* 4950cfc6e8dSAlexander Graf * We have to generate ser1 first, because Linux takes the first 4960cfc6e8dSAlexander Graf * device it finds in the dt as serial output device. And we generate 4970cfc6e8dSAlexander Graf * devices in reverse order to the dt. 4980cfc6e8dSAlexander Graf */ 4999bca0edbSPeter Maydell if (serial_hd(1)) { 500dffb1dc2SBharat Bhushan dt_serial_create(fdt, MPC8544_SERIAL1_REGS_OFFSET, 501a053a7ceSAlexander Graf soc, mpic, "serial1", 1, false); 50279c0ff2cSAlexander Graf } 50379c0ff2cSAlexander Graf 5049bca0edbSPeter Maydell if (serial_hd(0)) { 505dffb1dc2SBharat Bhushan dt_serial_create(fdt, MPC8544_SERIAL0_REGS_OFFSET, 506a053a7ceSAlexander Graf soc, mpic, "serial0", 0, true); 50779c0ff2cSAlexander Graf } 5080cfc6e8dSAlexander Graf 5097abb479cSAndrew Randrianasulu /* i2c */ 5107abb479cSAndrew Randrianasulu dt_i2c_create(fdt, soc, mpic, "i2c"); 5117abb479cSAndrew Randrianasulu 5127abb479cSAndrew Randrianasulu dt_rtc_create(fdt, "i2c", "rtc"); 5137abb479cSAndrew Randrianasulu 5147abb479cSAndrew Randrianasulu 5152fb513d3SGreg Kurz gutil = g_strdup_printf("%s/global-utilities@%llx", soc, 516dffb1dc2SBharat Bhushan MPC8544_UTIL_OFFSET); 5175a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, gutil); 5185a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, gutil, "compatible", "fsl,mpc8544-guts"); 5195a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, gutil, "reg", MPC8544_UTIL_OFFSET, 0x1000); 5205a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, gutil, "fsl,has-rstcr", NULL, 0); 5212fb513d3SGreg Kurz g_free(gutil); 522f5038483SAlexander Graf 5232fb513d3SGreg Kurz msi = g_strdup_printf("/%s/msi@%llx", soc, MPC8544_MSI_REGS_OFFSET); 5245a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, msi); 5255a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, msi, "compatible", "fsl,mpic-msi"); 5265a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, msi, "reg", MPC8544_MSI_REGS_OFFSET, 0x200); 5275a4348d1SPeter Crosthwaite msi_ph = qemu_fdt_alloc_phandle(fdt); 5285a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, msi, "msi-available-ranges", 0x0, 0x100); 5295a4348d1SPeter Crosthwaite qemu_fdt_setprop_phandle(fdt, msi, "interrupt-parent", mpic); 5305a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, msi, "interrupts", 531a911b7a9SAlexander Graf 0xe0, 0x0, 532a911b7a9SAlexander Graf 0xe1, 0x0, 533a911b7a9SAlexander Graf 0xe2, 0x0, 534a911b7a9SAlexander Graf 0xe3, 0x0, 535a911b7a9SAlexander Graf 0xe4, 0x0, 536a911b7a9SAlexander Graf 0xe5, 0x0, 537a911b7a9SAlexander Graf 0xe6, 0x0, 538a911b7a9SAlexander Graf 0xe7, 0x0); 5395a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, msi, "phandle", msi_ph); 5405a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, msi, "linux,phandle", msi_ph); 5412fb513d3SGreg Kurz g_free(msi); 542a911b7a9SAlexander Graf 5432fb513d3SGreg Kurz pci = g_strdup_printf("/pci@%llx", 54403f04809SIgor Mammedov pmc->ccsrbar_base + MPC8544_PCI_REGS_OFFSET); 5455a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, pci); 5465a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, pci, "cell-index", 0); 5475a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, pci, "compatible", "fsl,mpc8540-pci"); 5485a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, pci, "device_type", "pci"); 5495a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, pci, "interrupt-map-mask", 0xf800, 0x0, 5500dbc0798SAlexander Graf 0x0, 0x7); 5515a4348d1SPeter Crosthwaite pci_map = pci_map_create(fdt, qemu_fdt_get_phandle(fdt, mpic), 55203f04809SIgor Mammedov pmc->pci_first_slot, pmc->pci_nr_slots, 553492ec48dSAlexander Graf &len); 5545a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, pci, "interrupt-map", pci_map, len); 5555a4348d1SPeter Crosthwaite qemu_fdt_setprop_phandle(fdt, pci, "interrupt-parent", mpic); 5565a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, pci, "interrupts", 24, 2); 5575a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, pci, "bus-range", 0, 255); 5583627757eSAlexander Graf for (i = 0; i < 14; i++) { 5590dbc0798SAlexander Graf pci_ranges[i] = cpu_to_be32(pci_ranges[i]); 5600dbc0798SAlexander Graf } 5615a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, pci, "fsl,msi", msi_ph); 5625a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, pci, "ranges", pci_ranges, sizeof(pci_ranges)); 5632eaaac1fSAlexander Graf qemu_fdt_setprop_cells(fdt, pci, "reg", 56403f04809SIgor Mammedov (pmc->ccsrbar_base + MPC8544_PCI_REGS_OFFSET) >> 32, 56503f04809SIgor Mammedov (pmc->ccsrbar_base + MPC8544_PCI_REGS_OFFSET), 5662eaaac1fSAlexander Graf 0, 0x1000); 5675a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, pci, "clock-frequency", 66666666); 5685a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, pci, "#interrupt-cells", 1); 5695a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, pci, "#size-cells", 2); 5705a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, pci, "#address-cells", 3); 5715a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, "/aliases", "pci0", pci); 5722fb513d3SGreg Kurz g_free(pci); 5730dbc0798SAlexander Graf 57403f04809SIgor Mammedov if (pmc->has_mpc8xxx_gpio) { 575b88e77f4SAlexander Graf create_dt_mpc8xxx_gpio(fdt, soc, mpic); 576b88e77f4SAlexander Graf } 5772fb513d3SGreg Kurz g_free(soc); 578b88e77f4SAlexander Graf 579a3fc8396SIgor Mammedov if (pms->pbus_dev) { 580a3fc8396SIgor Mammedov platform_bus_create_devtree(pms, fdt, mpic); 581f7087343SAlexander Graf } 5822fb513d3SGreg Kurz g_free(mpic); 583f7087343SAlexander Graf 58403f04809SIgor Mammedov pmc->fixup_devtree(fdt); 585e6eaabebSScott Wood 586e6eaabebSScott Wood if (toplevel_compat) { 5875a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, "/", "compatible", toplevel_compat, 588e6eaabebSScott Wood strlen(toplevel_compat) + 1); 589e6eaabebSScott Wood } 590e6eaabebSScott Wood 591d1b93565SAlexander Graf done: 59228290f37SAlexander Graf if (!dry_run) { 5935a4348d1SPeter Crosthwaite qemu_fdt_dumpdtb(fdt, fdt_size); 59428290f37SAlexander Graf cpu_physical_memory_write(addr, fdt, fdt_size); 595cba2026aSAlexander Graf } 596cba2026aSAlexander Graf ret = fdt_size; 597b2fb7a43SPan Nengyuan g_free(fdt); 5987ec632b4Spbrook 5991db09b84Saurel32 out: 600347dd79dSAlexander Graf g_free(pci_map); 6011db09b84Saurel32 60204088adbSLiu Yu return ret; 6031db09b84Saurel32 } 6041db09b84Saurel32 60528290f37SAlexander Graf typedef struct DeviceTreeParams { 60603f04809SIgor Mammedov PPCE500MachineState *machine; 60728290f37SAlexander Graf hwaddr addr; 60828290f37SAlexander Graf hwaddr initrd_base; 60928290f37SAlexander Graf hwaddr initrd_size; 610903585deSAlexander Graf hwaddr kernel_base; 611903585deSAlexander Graf hwaddr kernel_size; 612f7087343SAlexander Graf Notifier notifier; 61328290f37SAlexander Graf } DeviceTreeParams; 61428290f37SAlexander Graf 61528290f37SAlexander Graf static void ppce500_reset_device_tree(void *opaque) 61628290f37SAlexander Graf { 61728290f37SAlexander Graf DeviceTreeParams *p = opaque; 61803f04809SIgor Mammedov ppce500_load_device_tree(p->machine, p->addr, p->initrd_base, 619903585deSAlexander Graf p->initrd_size, p->kernel_base, p->kernel_size, 620903585deSAlexander Graf false); 62128290f37SAlexander Graf } 62228290f37SAlexander Graf 623f7087343SAlexander Graf static void ppce500_init_notify(Notifier *notifier, void *data) 624f7087343SAlexander Graf { 625f7087343SAlexander Graf DeviceTreeParams *p = container_of(notifier, DeviceTreeParams, notifier); 626f7087343SAlexander Graf ppce500_reset_device_tree(p); 627f7087343SAlexander Graf } 628f7087343SAlexander Graf 62903f04809SIgor Mammedov static int ppce500_prep_device_tree(PPCE500MachineState *machine, 63028290f37SAlexander Graf hwaddr addr, 63128290f37SAlexander Graf hwaddr initrd_base, 632903585deSAlexander Graf hwaddr initrd_size, 633903585deSAlexander Graf hwaddr kernel_base, 634903585deSAlexander Graf hwaddr kernel_size) 63528290f37SAlexander Graf { 63628290f37SAlexander Graf DeviceTreeParams *p = g_new(DeviceTreeParams, 1); 6373ef96221SMarcel Apfelbaum p->machine = machine; 63828290f37SAlexander Graf p->addr = addr; 63928290f37SAlexander Graf p->initrd_base = initrd_base; 64028290f37SAlexander Graf p->initrd_size = initrd_size; 641903585deSAlexander Graf p->kernel_base = kernel_base; 642903585deSAlexander Graf p->kernel_size = kernel_size; 64328290f37SAlexander Graf 64428290f37SAlexander Graf qemu_register_reset(ppce500_reset_device_tree, p); 645f7087343SAlexander Graf p->notifier.notify = ppce500_init_notify; 646f7087343SAlexander Graf qemu_add_machine_init_done_notifier(&p->notifier); 64728290f37SAlexander Graf 64828290f37SAlexander Graf /* Issue the device tree loader once, so that we get the size of the blob */ 64903f04809SIgor Mammedov return ppce500_load_device_tree(machine, addr, initrd_base, initrd_size, 65003f04809SIgor Mammedov kernel_base, kernel_size, true); 65128290f37SAlexander Graf } 65228290f37SAlexander Graf 653cba2026aSAlexander Graf /* Create -kernel TLB entries for BookE. */ 654a36848ffSAaron Larson hwaddr booke206_page_size_to_tlb(uint64_t size) 655d1e256feSAlexander Graf { 656ab3dd749SPhilippe Mathieu-Daudé return 63 - clz64(size / KiB); 657d1e256feSAlexander Graf } 658d1e256feSAlexander Graf 659cefd3cdbSBharat Bhushan static int booke206_initial_map_tsize(CPUPPCState *env) 6603b989d49SAlexander Graf { 661cba2026aSAlexander Graf struct boot_info *bi = env->load_info; 662cefd3cdbSBharat Bhushan hwaddr dt_end; 663cba2026aSAlexander Graf int ps; 6643b989d49SAlexander Graf 665cba2026aSAlexander Graf /* Our initial TLB entry needs to cover everything from 0 to 666cba2026aSAlexander Graf the device tree top */ 667cba2026aSAlexander Graf dt_end = bi->dt_base + bi->dt_size; 668cba2026aSAlexander Graf ps = booke206_page_size_to_tlb(dt_end) + 1; 669fb37c302SAlexander Graf if (ps & 1) { 670fb37c302SAlexander Graf /* e500v2 can only do even TLB size bits */ 671fb37c302SAlexander Graf ps++; 672fb37c302SAlexander Graf } 673cefd3cdbSBharat Bhushan return ps; 674cefd3cdbSBharat Bhushan } 675cefd3cdbSBharat Bhushan 676cefd3cdbSBharat Bhushan static uint64_t mmubooke_initial_mapsize(CPUPPCState *env) 677cefd3cdbSBharat Bhushan { 678cefd3cdbSBharat Bhushan int tsize; 679cefd3cdbSBharat Bhushan 680cefd3cdbSBharat Bhushan tsize = booke206_initial_map_tsize(env); 681cefd3cdbSBharat Bhushan return (1ULL << 10 << tsize); 682cefd3cdbSBharat Bhushan } 683cefd3cdbSBharat Bhushan 684cefd3cdbSBharat Bhushan static void mmubooke_create_initial_mapping(CPUPPCState *env) 685cefd3cdbSBharat Bhushan { 686cefd3cdbSBharat Bhushan ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0); 687cefd3cdbSBharat Bhushan hwaddr size; 688cefd3cdbSBharat Bhushan int ps; 689cefd3cdbSBharat Bhushan 690cefd3cdbSBharat Bhushan ps = booke206_initial_map_tsize(env); 691cba2026aSAlexander Graf size = (ps << MAS1_TSIZE_SHIFT); 692d1e256feSAlexander Graf tlb->mas1 = MAS1_VALID | size; 693cba2026aSAlexander Graf tlb->mas2 = 0; 694cba2026aSAlexander Graf tlb->mas7_3 = 0; 695d1e256feSAlexander Graf tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX; 69693dd5e85SScott Wood 69793dd5e85SScott Wood env->tlb_dirty = true; 6983b989d49SAlexander Graf } 6993b989d49SAlexander Graf 700b3305981SScott Wood static void ppce500_cpu_reset_sec(void *opaque) 7015c145dacSAlexander Graf { 70238f92da6SAndreas Färber PowerPCCPU *cpu = opaque; 703259186a7SAndreas Färber CPUState *cs = CPU(cpu); 7045c145dacSAlexander Graf 705259186a7SAndreas Färber cpu_reset(cs); 7065c145dacSAlexander Graf 7075c145dacSAlexander Graf /* Secondary CPU starts in halted state for now. Needs to change when 7085c145dacSAlexander Graf implementing non-kernel boot. */ 709259186a7SAndreas Färber cs->halted = 1; 71027103424SAndreas Färber cs->exception_index = EXCP_HLT; 7113b989d49SAlexander Graf } 7123b989d49SAlexander Graf 713b3305981SScott Wood static void ppce500_cpu_reset(void *opaque) 7143b989d49SAlexander Graf { 71538f92da6SAndreas Färber PowerPCCPU *cpu = opaque; 716259186a7SAndreas Färber CPUState *cs = CPU(cpu); 71738f92da6SAndreas Färber CPUPPCState *env = &cpu->env; 7183b989d49SAlexander Graf struct boot_info *bi = env->load_info; 7193b989d49SAlexander Graf 720259186a7SAndreas Färber cpu_reset(cs); 7213b989d49SAlexander Graf 7223b989d49SAlexander Graf /* Set initial guest state. */ 723259186a7SAndreas Färber cs->halted = 0; 724ab3dd749SPhilippe Mathieu-Daudé env->gpr[1] = (16 * MiB) - 8; 7253b989d49SAlexander Graf env->gpr[3] = bi->dt_base; 726cefd3cdbSBharat Bhushan env->gpr[4] = 0; 727cefd3cdbSBharat Bhushan env->gpr[5] = 0; 728cefd3cdbSBharat Bhushan env->gpr[6] = EPAPR_MAGIC; 729cefd3cdbSBharat Bhushan env->gpr[7] = mmubooke_initial_mapsize(env); 730cefd3cdbSBharat Bhushan env->gpr[8] = 0; 731cefd3cdbSBharat Bhushan env->gpr[9] = 0; 7323b989d49SAlexander Graf env->nip = bi->entry; 733cba2026aSAlexander Graf mmubooke_create_initial_mapping(env); 7343b989d49SAlexander Graf } 7353b989d49SAlexander Graf 73603f04809SIgor Mammedov static DeviceState *ppce500_init_mpic_qemu(PPCE500MachineState *pms, 7372104d4f5SGreg Kurz IrqLines *irqs) 73882fc73b6SScott Wood { 73982fc73b6SScott Wood DeviceState *dev; 74082fc73b6SScott Wood SysBusDevice *s; 74182fc73b6SScott Wood int i, j, k; 74203f04809SIgor Mammedov MachineState *machine = MACHINE(pms); 743fe6b6346SLike Xu unsigned int smp_cpus = machine->smp.cpus; 74403f04809SIgor Mammedov const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(pms); 74582fc73b6SScott Wood 7463e80f690SMarkus Armbruster dev = qdev_new(TYPE_OPENPIC); 747d2623129SMarkus Armbruster object_property_add_child(OBJECT(machine), "pic", OBJECT(dev)); 74803f04809SIgor Mammedov qdev_prop_set_uint32(dev, "model", pmc->mpic_version); 749d85937e6SScott Wood qdev_prop_set_uint32(dev, "nb_cpus", smp_cpus); 750d85937e6SScott Wood 75182fc73b6SScott Wood s = SYS_BUS_DEVICE(dev); 7523c6ef471SMarkus Armbruster sysbus_realize_and_unref(s, &error_fatal); 75382fc73b6SScott Wood 75482fc73b6SScott Wood k = 0; 75582fc73b6SScott Wood for (i = 0; i < smp_cpus; i++) { 75682fc73b6SScott Wood for (j = 0; j < OPENPIC_OUTPUT_NB; j++) { 7572104d4f5SGreg Kurz sysbus_connect_irq(s, k++, irqs[i].irq[j]); 75882fc73b6SScott Wood } 75982fc73b6SScott Wood } 76082fc73b6SScott Wood 761d85937e6SScott Wood return dev; 762d85937e6SScott Wood } 763d85937e6SScott Wood 76403f04809SIgor Mammedov static DeviceState *ppce500_init_mpic_kvm(const PPCE500MachineClass *pmc, 7652104d4f5SGreg Kurz IrqLines *irqs, Error **errp) 766d85937e6SScott Wood { 767d85937e6SScott Wood DeviceState *dev; 768d85937e6SScott Wood CPUState *cs; 769d85937e6SScott Wood 7703e80f690SMarkus Armbruster dev = qdev_new(TYPE_KVM_OPENPIC); 77103f04809SIgor Mammedov qdev_prop_set_uint32(dev, "model", pmc->mpic_version); 772d85937e6SScott Wood 773668f62ecSMarkus Armbruster if (!sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), errp)) { 774fe656ebdSMarkus Armbruster object_unparent(OBJECT(dev)); 775d85937e6SScott Wood return NULL; 776d85937e6SScott Wood } 777d85937e6SScott Wood 778bdc44640SAndreas Färber CPU_FOREACH(cs) { 779d85937e6SScott Wood if (kvm_openpic_connect_vcpu(dev, cs)) { 780d85937e6SScott Wood fprintf(stderr, "%s: failed to connect vcpu to irqchip\n", 781d85937e6SScott Wood __func__); 782d85937e6SScott Wood abort(); 783d85937e6SScott Wood } 784d85937e6SScott Wood } 785d85937e6SScott Wood 786d85937e6SScott Wood return dev; 787d85937e6SScott Wood } 788d85937e6SScott Wood 78903f04809SIgor Mammedov static DeviceState *ppce500_init_mpic(PPCE500MachineState *pms, 790c91c187fSMichael Davidsaver MemoryRegion *ccsr, 7912104d4f5SGreg Kurz IrqLines *irqs) 792d85937e6SScott Wood { 79303f04809SIgor Mammedov const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(pms); 794d85937e6SScott Wood DeviceState *dev = NULL; 795d85937e6SScott Wood SysBusDevice *s; 796d85937e6SScott Wood 797d85937e6SScott Wood if (kvm_enabled()) { 798fe656ebdSMarkus Armbruster Error *err = NULL; 799d85937e6SScott Wood 8004376c40dSPaolo Bonzini if (kvm_kernel_irqchip_allowed()) { 80103f04809SIgor Mammedov dev = ppce500_init_mpic_kvm(pmc, irqs, &err); 802d85937e6SScott Wood } 8034376c40dSPaolo Bonzini if (kvm_kernel_irqchip_required() && !dev) { 804c29b77f9SMarkus Armbruster error_reportf_err(err, 805c29b77f9SMarkus Armbruster "kernel_irqchip requested but unavailable: "); 806fe656ebdSMarkus Armbruster exit(1); 807d85937e6SScott Wood } 808d85937e6SScott Wood } 809d85937e6SScott Wood 810d85937e6SScott Wood if (!dev) { 81103f04809SIgor Mammedov dev = ppce500_init_mpic_qemu(pms, irqs); 812d85937e6SScott Wood } 813d85937e6SScott Wood 814d85937e6SScott Wood s = SYS_BUS_DEVICE(dev); 81582fc73b6SScott Wood memory_region_add_subregion(ccsr, MPC8544_MPIC_REGS_OFFSET, 81682fc73b6SScott Wood s->mmio[0].memory); 81782fc73b6SScott Wood 818c91c187fSMichael Davidsaver return dev; 81982fc73b6SScott Wood } 82082fc73b6SScott Wood 821016f7758SAlexander Graf static void ppce500_power_off(void *opaque, int line, int on) 822016f7758SAlexander Graf { 823016f7758SAlexander Graf if (on) { 824cf83f140SEric Blake qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); 825016f7758SAlexander Graf } 826016f7758SAlexander Graf } 827016f7758SAlexander Graf 82803f04809SIgor Mammedov void ppce500_init(MachineState *machine) 8291db09b84Saurel32 { 83039186d8aSRichard Henderson MemoryRegion *address_space_mem = get_system_memory(); 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; 850fe6b6346SLike Xu unsigned int smp_cpus = machine->smp.cpus; 851d575a6ceSBharat Bhushan /* irq num for pin INTA, INTB, INTC and INTD is 1, 2, 3 and 852d575a6ceSBharat Bhushan * 4 respectively */ 853d575a6ceSBharat Bhushan unsigned int pci_irq_nrs[PCI_NUM_PINS] = {1, 2, 3, 4}; 8542104d4f5SGreg Kurz IrqLines *irqs; 855c91c187fSMichael Davidsaver DeviceState *dev, *mpicdev; 856e2684c0bSAndreas Färber CPUPPCState *firstenv = NULL; 8573eddc1beSBharat Bhushan MemoryRegion *ccsr_addr_space; 858dffb1dc2SBharat Bhushan SysBusDevice *s; 8593eddc1beSBharat Bhushan PPCE500CCSRState *ccsr; 8607abb479cSAndrew Randrianasulu I2CBus *i2c; 8611db09b84Saurel32 8622104d4f5SGreg Kurz irqs = g_new0(IrqLines, smp_cpus); 863e61c36d5SAlexander Graf for (i = 0; i < smp_cpus; i++) { 864397b457dSAndreas Färber PowerPCCPU *cpu; 86555e5c285SAndreas Färber CPUState *cs; 866e61c36d5SAlexander Graf qemu_irq *input; 867397b457dSAndreas Färber 86859e816fdSIgor Mammedov cpu = POWERPC_CPU(cpu_create(machine->cpu_type)); 869397b457dSAndreas Färber env = &cpu->env; 87055e5c285SAndreas Färber cs = CPU(cpu); 8711db09b84Saurel32 87200469dc3SValentin Plotkin if (env->mmu_model != POWERPC_MMU_BOOKE206) { 8736f76b817SAlistair Francis error_report("MMU model %i not supported by this machine", 87400469dc3SValentin Plotkin env->mmu_model); 87500469dc3SValentin Plotkin exit(1); 87600469dc3SValentin Plotkin } 87700469dc3SValentin Plotkin 878e61c36d5SAlexander Graf if (!firstenv) { 879e61c36d5SAlexander Graf firstenv = env; 880e61c36d5SAlexander Graf } 881e61c36d5SAlexander Graf 882a915249fSAlexander Graf input = (qemu_irq *)env->irq_inputs; 8832104d4f5SGreg Kurz irqs[i].irq[OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT]; 8842104d4f5SGreg Kurz irqs[i].irq[OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT]; 8856a450df9SAlexander Graf env->spr_cb[SPR_BOOKE_PIR].default_value = cs->cpu_index = i; 88603f04809SIgor Mammedov env->mpic_iack = pmc->ccsrbar_base + MPC8544_MPIC_REGS_OFFSET + 0xa0; 887e61c36d5SAlexander Graf 888a34a92b9SAndreas Färber ppc_booke_timers_init(cpu, 400000000, PPC_TIMER_E500); 8893b989d49SAlexander Graf 8903b989d49SAlexander Graf /* Register reset handler */ 8915c145dacSAlexander Graf if (!i) { 8925c145dacSAlexander Graf /* Primary CPU */ 8935c145dacSAlexander Graf struct boot_info *boot_info; 894e61c36d5SAlexander Graf boot_info = g_malloc0(sizeof(struct boot_info)); 895b3305981SScott Wood qemu_register_reset(ppce500_cpu_reset, cpu); 896e61c36d5SAlexander Graf env->load_info = boot_info; 8975c145dacSAlexander Graf } else { 8985c145dacSAlexander Graf /* Secondary CPUs */ 899b3305981SScott Wood qemu_register_reset(ppce500_cpu_reset_sec, cpu); 9005c145dacSAlexander Graf } 901e61c36d5SAlexander Graf } 902e61c36d5SAlexander Graf 903e61c36d5SAlexander Graf env = firstenv; 9043b989d49SAlexander Graf 9053538e846SIgor Mammedov if (!QEMU_IS_ALIGNED(machine->ram_size, RAM_SIZES_ALIGN)) { 9063538e846SIgor Mammedov error_report("RAM size must be multiple of %" PRIu64, RAM_SIZES_ALIGN); 9073538e846SIgor Mammedov exit(EXIT_FAILURE); 9083538e846SIgor Mammedov } 9091db09b84Saurel32 9101db09b84Saurel32 /* Register Memory */ 91197316645SIgor Mammedov memory_region_add_subregion(address_space_mem, 0, machine->ram); 9121db09b84Saurel32 9133e80f690SMarkus Armbruster dev = qdev_new("e500-ccsr"); 9143eddc1beSBharat Bhushan object_property_add_child(qdev_get_machine(), "e500-ccsr", 915d2623129SMarkus Armbruster OBJECT(dev)); 9163c6ef471SMarkus Armbruster sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); 9173eddc1beSBharat Bhushan ccsr = CCSR(dev); 9183eddc1beSBharat Bhushan ccsr_addr_space = &ccsr->ccsr_space; 91903f04809SIgor Mammedov memory_region_add_subregion(address_space_mem, pmc->ccsrbar_base, 9203eddc1beSBharat Bhushan ccsr_addr_space); 921dffb1dc2SBharat Bhushan 92203f04809SIgor Mammedov mpicdev = ppce500_init_mpic(pms, ccsr_addr_space, irqs); 9231db09b84Saurel32 9241db09b84Saurel32 /* Serial */ 9259bca0edbSPeter Maydell if (serial_hd(0)) { 9263eddc1beSBharat Bhushan serial_mm_init(ccsr_addr_space, MPC8544_SERIAL0_REGS_OFFSET, 927c91c187fSMichael Davidsaver 0, qdev_get_gpio_in(mpicdev, 42), 399193, 9289bca0edbSPeter Maydell serial_hd(0), DEVICE_BIG_ENDIAN); 9292d48377aSBlue Swirl } 9301db09b84Saurel32 9319bca0edbSPeter Maydell if (serial_hd(1)) { 9323eddc1beSBharat Bhushan serial_mm_init(ccsr_addr_space, MPC8544_SERIAL1_REGS_OFFSET, 933c91c187fSMichael Davidsaver 0, qdev_get_gpio_in(mpicdev, 42), 399193, 9349bca0edbSPeter Maydell serial_hd(1), DEVICE_BIG_ENDIAN); 9352d48377aSBlue Swirl } 9367abb479cSAndrew Randrianasulu /* I2C */ 9373e80f690SMarkus Armbruster dev = qdev_new("mpc-i2c"); 9387abb479cSAndrew Randrianasulu s = SYS_BUS_DEVICE(dev); 9393c6ef471SMarkus Armbruster sysbus_realize_and_unref(s, &error_fatal); 9407abb479cSAndrew Randrianasulu sysbus_connect_irq(s, 0, qdev_get_gpio_in(mpicdev, MPC8544_I2C_IRQ)); 9417abb479cSAndrew Randrianasulu memory_region_add_subregion(ccsr_addr_space, MPC8544_I2C_REGS_OFFSET, 9427abb479cSAndrew Randrianasulu sysbus_mmio_get_region(s, 0)); 9437abb479cSAndrew Randrianasulu i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c"); 944*1373b15bSPhilippe Mathieu-Daudé i2c_slave_create_simple(i2c, "ds1338", RTC_REGS_OFFSET); 9457abb479cSAndrew Randrianasulu 9461db09b84Saurel32 947b0fb8423SAlexander Graf /* General Utility device */ 9483e80f690SMarkus Armbruster dev = qdev_new("mpc8544-guts"); 949dffb1dc2SBharat Bhushan s = SYS_BUS_DEVICE(dev); 9503c6ef471SMarkus Armbruster sysbus_realize_and_unref(s, &error_fatal); 9513eddc1beSBharat Bhushan memory_region_add_subregion(ccsr_addr_space, MPC8544_UTIL_OFFSET, 952dffb1dc2SBharat Bhushan sysbus_mmio_get_region(s, 0)); 953b0fb8423SAlexander Graf 9541db09b84Saurel32 /* PCI */ 9553e80f690SMarkus Armbruster dev = qdev_new("e500-pcihost"); 956d2623129SMarkus Armbruster object_property_add_child(qdev_get_machine(), "pci-host", OBJECT(dev)); 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 s = SYS_BUS_DEVICE(dev); 9603c6ef471SMarkus Armbruster sysbus_realize_and_unref(s, &error_fatal); 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 9853e80f690SMarkus Armbruster dev = qdev_new("mpc8xxx_gpio"); 986b88e77f4SAlexander Graf s = SYS_BUS_DEVICE(dev); 9873c6ef471SMarkus Armbruster sysbus_realize_and_unref(s, &error_fatal); 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) { 9993e80f690SMarkus Armbruster dev = qdev_new(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); 10033c6ef471SMarkus Armbruster sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); 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); 10453b4f50bdSPeter Maydell if (!filename) { 10463b4f50bdSPeter Maydell error_report("could not find firmware/kernel file '%s'", payload_name); 10473b4f50bdSPeter Maydell exit(1); 10483b4f50bdSPeter Maydell } 10498d622594SDavid Engraf 10504366e1dbSLiam Merwick payload_size = load_elf(filename, NULL, NULL, NULL, 10516cdda0ffSAleksandar Markovic &bios_entry, &loadaddr, NULL, NULL, 10528d622594SDavid Engraf 1, PPC_ELF_MACHINE, 0, 0); 10538d622594SDavid Engraf if (payload_size < 0) { 10548d622594SDavid Engraf /* 10558d622594SDavid Engraf * Hrm. No ELF image? Try a uImage, maybe someone is giving us an 10568d622594SDavid Engraf * ePAPR compliant kernel 10578d622594SDavid Engraf */ 1058f831f955SNick Hudson loadaddr = LOAD_UIMAGE_LOADADDR_INVALID; 10598d622594SDavid Engraf payload_size = load_uimage(filename, &bios_entry, &loadaddr, NULL, 10608d622594SDavid Engraf NULL, NULL); 10618d622594SDavid Engraf if (payload_size < 0) { 1062371b74e2SMao Zhongyi error_report("could not load firmware '%s'", filename); 10638d622594SDavid Engraf exit(1); 10648d622594SDavid Engraf } 10658d622594SDavid Engraf } 10668d622594SDavid Engraf 10678d622594SDavid Engraf g_free(filename); 10688d622594SDavid Engraf 10698d622594SDavid Engraf if (kernel_as_payload) { 10708d622594SDavid Engraf kernel_base = loadaddr; 10718d622594SDavid Engraf kernel_size = payload_size; 10728d622594SDavid Engraf } 10738d622594SDavid Engraf 10748d622594SDavid Engraf cur_base = loadaddr + payload_size; 1075ab3dd749SPhilippe Mathieu-Daudé if (cur_base < 32 * MiB) { 1076b4a5f24aSDavid Engraf /* u-boot occupies memory up to 32MB, so load blobs above */ 1077ab3dd749SPhilippe Mathieu-Daudé cur_base = 32 * MiB; 1078b4a5f24aSDavid Engraf } 10798d622594SDavid Engraf 10808d622594SDavid Engraf /* Load bare kernel only if no bios/u-boot has been provided */ 10818d622594SDavid Engraf if (machine->kernel_filename && !kernel_as_payload) { 10823812c71fSAlexander Graf kernel_base = cur_base; 10833812c71fSAlexander Graf kernel_size = load_image_targphys(machine->kernel_filename, 10843812c71fSAlexander Graf cur_base, 10853538e846SIgor Mammedov machine->ram_size - cur_base); 10861db09b84Saurel32 if (kernel_size < 0) { 10876f76b817SAlistair Francis error_report("could not load kernel '%s'", 10883ef96221SMarcel Apfelbaum machine->kernel_filename); 10891db09b84Saurel32 exit(1); 10901db09b84Saurel32 } 1091528e536eSAlexander Graf 10923812c71fSAlexander Graf cur_base += kernel_size; 10931db09b84Saurel32 } 10941db09b84Saurel32 10951db09b84Saurel32 /* Load initrd. */ 10963ef96221SMarcel Apfelbaum if (machine->initrd_filename) { 1097528e536eSAlexander Graf initrd_base = (cur_base + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK; 10983ef96221SMarcel Apfelbaum initrd_size = load_image_targphys(machine->initrd_filename, initrd_base, 10993538e846SIgor Mammedov machine->ram_size - initrd_base); 11001db09b84Saurel32 11011db09b84Saurel32 if (initrd_size < 0) { 11026f76b817SAlistair Francis error_report("could not load initial ram disk '%s'", 11033ef96221SMarcel Apfelbaum machine->initrd_filename); 11041db09b84Saurel32 exit(1); 11051db09b84Saurel32 } 1106528e536eSAlexander Graf 1107528e536eSAlexander Graf cur_base = initrd_base + initrd_size; 11081db09b84Saurel32 } 11091db09b84Saurel32 11103812c71fSAlexander Graf /* 11118d622594SDavid Engraf * Reserve space for dtb behind the kernel image because Linux has a bug 11128d622594SDavid Engraf * where it can only handle the dtb if it's within the first 64MB of where 11138d622594SDavid Engraf * <kernel> starts. dtb cannot not reach initrd_base because INITRD_LOAD_PAD 11148d622594SDavid Engraf * ensures enough space between kernel and initrd. 11153812c71fSAlexander Graf */ 11168d622594SDavid Engraf dt_base = (loadaddr + payload_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK; 11173538e846SIgor Mammedov if (dt_base + DTB_MAX_SIZE > machine->ram_size) { 1118371b74e2SMao Zhongyi error_report("not enough memory for device tree"); 11193812c71fSAlexander Graf exit(1); 11203812c71fSAlexander Graf } 11215c145dacSAlexander Graf 112203f04809SIgor Mammedov dt_size = ppce500_prep_device_tree(pms, dt_base, 1123903585deSAlexander Graf initrd_base, initrd_size, 11243812c71fSAlexander Graf kernel_base, kernel_size); 1125cba2026aSAlexander Graf if (dt_size < 0) { 11266f76b817SAlistair Francis error_report("couldn't load device tree"); 11271db09b84Saurel32 exit(1); 11281db09b84Saurel32 } 1129b8dec144SAlexander Graf assert(dt_size < DTB_MAX_SIZE); 11301db09b84Saurel32 1131e61c36d5SAlexander Graf boot_info = env->load_info; 11323812c71fSAlexander Graf boot_info->entry = bios_entry; 11333b989d49SAlexander Graf boot_info->dt_base = dt_base; 1134cba2026aSAlexander Graf boot_info->dt_size = dt_size; 11351db09b84Saurel32 } 11363eddc1beSBharat Bhushan 1137d0c2b0d0Sxiaoqiang zhao static void e500_ccsr_initfn(Object *obj) 11383eddc1beSBharat Bhushan { 1139d0c2b0d0Sxiaoqiang zhao PPCE500CCSRState *ccsr = CCSR(obj); 1140d0c2b0d0Sxiaoqiang zhao memory_region_init(&ccsr->ccsr_space, obj, "e500-ccsr", 11413eddc1beSBharat Bhushan MPC8544_CCSRBAR_SIZE); 11423eddc1beSBharat Bhushan } 11433eddc1beSBharat Bhushan 11443eddc1beSBharat Bhushan static const TypeInfo e500_ccsr_info = { 11453eddc1beSBharat Bhushan .name = TYPE_CCSR, 11463eddc1beSBharat Bhushan .parent = TYPE_SYS_BUS_DEVICE, 11473eddc1beSBharat Bhushan .instance_size = sizeof(PPCE500CCSRState), 1148d0c2b0d0Sxiaoqiang zhao .instance_init = e500_ccsr_initfn, 11493eddc1beSBharat Bhushan }; 11503eddc1beSBharat Bhushan 115103f04809SIgor Mammedov static const TypeInfo ppce500_info = { 115203f04809SIgor Mammedov .name = TYPE_PPCE500_MACHINE, 115303f04809SIgor Mammedov .parent = TYPE_MACHINE, 115403f04809SIgor Mammedov .abstract = true, 1155a3fc8396SIgor Mammedov .instance_size = sizeof(PPCE500MachineState), 115603f04809SIgor Mammedov .class_size = sizeof(PPCE500MachineClass), 115703f04809SIgor Mammedov }; 115803f04809SIgor Mammedov 11593eddc1beSBharat Bhushan static void e500_register_types(void) 11603eddc1beSBharat Bhushan { 11613eddc1beSBharat Bhushan type_register_static(&e500_ccsr_info); 116203f04809SIgor Mammedov type_register_static(&ppce500_info); 11633eddc1beSBharat Bhushan } 11643eddc1beSBharat Bhushan 11653eddc1beSBharat Bhushan type_init(e500_register_types) 1166