xref: /qemu/hw/ppc/e500.c (revision a8d2532645cf5ce4f75981f81dfe363efc35d05c)
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