xref: /qemu/hw/ppc/e500.c (revision cd7b94989a468bbdca40f663f35ce954c44a8c3f)
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 
70727103424SAndreas Färber     cs->exception_index = EXCP_HLT;
7083b989d49SAlexander Graf }
7093b989d49SAlexander Graf 
710b3305981SScott Wood static void ppce500_cpu_reset(void *opaque)
7113b989d49SAlexander Graf {
71238f92da6SAndreas Färber     PowerPCCPU *cpu = opaque;
713259186a7SAndreas Färber     CPUState *cs = CPU(cpu);
71438f92da6SAndreas Färber     CPUPPCState *env = &cpu->env;
7153b989d49SAlexander Graf     struct boot_info *bi = env->load_info;
7163b989d49SAlexander Graf 
717259186a7SAndreas Färber     cpu_reset(cs);
7183b989d49SAlexander Graf 
7193b989d49SAlexander Graf     /* Set initial guest state. */
720259186a7SAndreas Färber     cs->halted = 0;
721ab3dd749SPhilippe Mathieu-Daudé     env->gpr[1] = (16 * MiB) - 8;
7223b989d49SAlexander Graf     env->gpr[3] = bi->dt_base;
723cefd3cdbSBharat Bhushan     env->gpr[4] = 0;
724cefd3cdbSBharat Bhushan     env->gpr[5] = 0;
725cefd3cdbSBharat Bhushan     env->gpr[6] = EPAPR_MAGIC;
726cefd3cdbSBharat Bhushan     env->gpr[7] = mmubooke_initial_mapsize(env);
727cefd3cdbSBharat Bhushan     env->gpr[8] = 0;
728cefd3cdbSBharat Bhushan     env->gpr[9] = 0;
7293b989d49SAlexander Graf     env->nip = bi->entry;
730cba2026aSAlexander Graf     mmubooke_create_initial_mapping(env);
7313b989d49SAlexander Graf }
7323b989d49SAlexander Graf 
73303f04809SIgor Mammedov static DeviceState *ppce500_init_mpic_qemu(PPCE500MachineState *pms,
7342104d4f5SGreg Kurz                                            IrqLines  *irqs)
73582fc73b6SScott Wood {
73682fc73b6SScott Wood     DeviceState *dev;
73782fc73b6SScott Wood     SysBusDevice *s;
73882fc73b6SScott Wood     int i, j, k;
73903f04809SIgor Mammedov     MachineState *machine = MACHINE(pms);
740fe6b6346SLike Xu     unsigned int smp_cpus = machine->smp.cpus;
74103f04809SIgor Mammedov     const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(pms);
74282fc73b6SScott Wood 
7433e80f690SMarkus Armbruster     dev = qdev_new(TYPE_OPENPIC);
744d2623129SMarkus Armbruster     object_property_add_child(OBJECT(machine), "pic", OBJECT(dev));
74503f04809SIgor Mammedov     qdev_prop_set_uint32(dev, "model", pmc->mpic_version);
746d85937e6SScott Wood     qdev_prop_set_uint32(dev, "nb_cpus", smp_cpus);
747d85937e6SScott Wood 
74882fc73b6SScott Wood     s = SYS_BUS_DEVICE(dev);
7493c6ef471SMarkus Armbruster     sysbus_realize_and_unref(s, &error_fatal);
75082fc73b6SScott Wood 
75182fc73b6SScott Wood     k = 0;
75282fc73b6SScott Wood     for (i = 0; i < smp_cpus; i++) {
75382fc73b6SScott Wood         for (j = 0; j < OPENPIC_OUTPUT_NB; j++) {
7542104d4f5SGreg Kurz             sysbus_connect_irq(s, k++, irqs[i].irq[j]);
75582fc73b6SScott Wood         }
75682fc73b6SScott Wood     }
75782fc73b6SScott Wood 
758d85937e6SScott Wood     return dev;
759d85937e6SScott Wood }
760d85937e6SScott Wood 
76103f04809SIgor Mammedov static DeviceState *ppce500_init_mpic_kvm(const PPCE500MachineClass *pmc,
7622104d4f5SGreg Kurz                                           IrqLines *irqs, Error **errp)
763d85937e6SScott Wood {
764d85937e6SScott Wood     DeviceState *dev;
765d85937e6SScott Wood     CPUState *cs;
766d85937e6SScott Wood 
7673e80f690SMarkus Armbruster     dev = qdev_new(TYPE_KVM_OPENPIC);
76803f04809SIgor Mammedov     qdev_prop_set_uint32(dev, "model", pmc->mpic_version);
769d85937e6SScott Wood 
770668f62ecSMarkus Armbruster     if (!sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), errp)) {
771fe656ebdSMarkus Armbruster         object_unparent(OBJECT(dev));
772d85937e6SScott Wood         return NULL;
773d85937e6SScott Wood     }
774d85937e6SScott Wood 
775bdc44640SAndreas Färber     CPU_FOREACH(cs) {
776d85937e6SScott Wood         if (kvm_openpic_connect_vcpu(dev, cs)) {
777d85937e6SScott Wood             fprintf(stderr, "%s: failed to connect vcpu to irqchip\n",
778d85937e6SScott Wood                     __func__);
779d85937e6SScott Wood             abort();
780d85937e6SScott Wood         }
781d85937e6SScott Wood     }
782d85937e6SScott Wood 
783d85937e6SScott Wood     return dev;
784d85937e6SScott Wood }
785d85937e6SScott Wood 
78603f04809SIgor Mammedov static DeviceState *ppce500_init_mpic(PPCE500MachineState *pms,
787c91c187fSMichael Davidsaver                                       MemoryRegion *ccsr,
7882104d4f5SGreg Kurz                                       IrqLines *irqs)
789d85937e6SScott Wood {
79003f04809SIgor Mammedov     const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(pms);
791d85937e6SScott Wood     DeviceState *dev = NULL;
792d85937e6SScott Wood     SysBusDevice *s;
793d85937e6SScott Wood 
794d85937e6SScott Wood     if (kvm_enabled()) {
795fe656ebdSMarkus Armbruster         Error *err = NULL;
796d85937e6SScott Wood 
7974376c40dSPaolo Bonzini         if (kvm_kernel_irqchip_allowed()) {
79803f04809SIgor Mammedov             dev = ppce500_init_mpic_kvm(pmc, irqs, &err);
799d85937e6SScott Wood         }
8004376c40dSPaolo Bonzini         if (kvm_kernel_irqchip_required() && !dev) {
801c29b77f9SMarkus Armbruster             error_reportf_err(err,
802c29b77f9SMarkus Armbruster                               "kernel_irqchip requested but unavailable: ");
803fe656ebdSMarkus Armbruster             exit(1);
804d85937e6SScott Wood         }
805d85937e6SScott Wood     }
806d85937e6SScott Wood 
807d85937e6SScott Wood     if (!dev) {
80803f04809SIgor Mammedov         dev = ppce500_init_mpic_qemu(pms, irqs);
809d85937e6SScott Wood     }
810d85937e6SScott Wood 
811d85937e6SScott Wood     s = SYS_BUS_DEVICE(dev);
81282fc73b6SScott Wood     memory_region_add_subregion(ccsr, MPC8544_MPIC_REGS_OFFSET,
81382fc73b6SScott Wood                                 s->mmio[0].memory);
81482fc73b6SScott Wood 
815c91c187fSMichael Davidsaver     return dev;
81682fc73b6SScott Wood }
81782fc73b6SScott Wood 
818016f7758SAlexander Graf static void ppce500_power_off(void *opaque, int line, int on)
819016f7758SAlexander Graf {
820016f7758SAlexander Graf     if (on) {
821cf83f140SEric Blake         qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
822016f7758SAlexander Graf     }
823016f7758SAlexander Graf }
824016f7758SAlexander Graf 
82503f04809SIgor Mammedov void ppce500_init(MachineState *machine)
8261db09b84Saurel32 {
82739186d8aSRichard Henderson     MemoryRegion *address_space_mem = get_system_memory();
82803f04809SIgor Mammedov     PPCE500MachineState *pms = PPCE500_MACHINE(machine);
82903f04809SIgor Mammedov     const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(machine);
8301db09b84Saurel32     PCIBus *pci_bus;
831e2684c0bSAndreas Färber     CPUPPCState *env = NULL;
8323812c71fSAlexander Graf     uint64_t loadaddr;
8333812c71fSAlexander Graf     hwaddr kernel_base = -1LL;
8343812c71fSAlexander Graf     int kernel_size = 0;
8353812c71fSAlexander Graf     hwaddr dt_base = 0;
8363812c71fSAlexander Graf     hwaddr initrd_base = 0;
8373812c71fSAlexander Graf     int initrd_size = 0;
8383812c71fSAlexander Graf     hwaddr cur_base = 0;
8393812c71fSAlexander Graf     char *filename;
8408d622594SDavid Engraf     const char *payload_name;
8418d622594SDavid Engraf     bool kernel_as_payload;
8423812c71fSAlexander Graf     hwaddr bios_entry = 0;
8438d622594SDavid Engraf     target_long payload_size;
8443812c71fSAlexander Graf     struct boot_info *boot_info;
8453812c71fSAlexander Graf     int dt_size;
84682fc73b6SScott Wood     int i;
847fe6b6346SLike Xu     unsigned int smp_cpus = machine->smp.cpus;
848d575a6ceSBharat Bhushan     /* irq num for pin INTA, INTB, INTC and INTD is 1, 2, 3 and
849d575a6ceSBharat Bhushan      * 4 respectively */
850d575a6ceSBharat Bhushan     unsigned int pci_irq_nrs[PCI_NUM_PINS] = {1, 2, 3, 4};
8512104d4f5SGreg Kurz     IrqLines *irqs;
852c91c187fSMichael Davidsaver     DeviceState *dev, *mpicdev;
853e2684c0bSAndreas Färber     CPUPPCState *firstenv = NULL;
8543eddc1beSBharat Bhushan     MemoryRegion *ccsr_addr_space;
855dffb1dc2SBharat Bhushan     SysBusDevice *s;
8563eddc1beSBharat Bhushan     PPCE500CCSRState *ccsr;
8577abb479cSAndrew Randrianasulu     I2CBus *i2c;
8581db09b84Saurel32 
8592104d4f5SGreg Kurz     irqs = g_new0(IrqLines, smp_cpus);
860e61c36d5SAlexander Graf     for (i = 0; i < smp_cpus; i++) {
861397b457dSAndreas Färber         PowerPCCPU *cpu;
86255e5c285SAndreas Färber         CPUState *cs;
863e61c36d5SAlexander Graf         qemu_irq *input;
864397b457dSAndreas Färber 
865a2c93f06SThiago Jung Bauermann         cpu = POWERPC_CPU(object_new(machine->cpu_type));
866397b457dSAndreas Färber         env = &cpu->env;
86755e5c285SAndreas Färber         cs = CPU(cpu);
8681db09b84Saurel32 
86900469dc3SValentin Plotkin         if (env->mmu_model != POWERPC_MMU_BOOKE206) {
8706f76b817SAlistair Francis             error_report("MMU model %i not supported by this machine",
87100469dc3SValentin Plotkin                          env->mmu_model);
87200469dc3SValentin Plotkin             exit(1);
87300469dc3SValentin Plotkin         }
87400469dc3SValentin Plotkin 
875a2c93f06SThiago Jung Bauermann         /*
876a2c93f06SThiago Jung Bauermann          * Secondary CPU starts in halted state for now. Needs to change
877a2c93f06SThiago Jung Bauermann          * when implementing non-kernel boot.
878a2c93f06SThiago Jung Bauermann          */
879a2c93f06SThiago Jung Bauermann         object_property_set_bool(OBJECT(cs), "start-powered-off", i != 0,
880a2c93f06SThiago Jung Bauermann                                  &error_fatal);
881a2c93f06SThiago Jung Bauermann         qdev_realize_and_unref(DEVICE(cs), NULL, &error_fatal);
882a2c93f06SThiago Jung Bauermann 
883e61c36d5SAlexander Graf         if (!firstenv) {
884e61c36d5SAlexander Graf             firstenv = env;
885e61c36d5SAlexander Graf         }
886e61c36d5SAlexander Graf 
887a915249fSAlexander Graf         input = (qemu_irq *)env->irq_inputs;
8882104d4f5SGreg Kurz         irqs[i].irq[OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT];
8892104d4f5SGreg Kurz         irqs[i].irq[OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT];
8906a450df9SAlexander Graf         env->spr_cb[SPR_BOOKE_PIR].default_value = cs->cpu_index = i;
89103f04809SIgor Mammedov         env->mpic_iack = pmc->ccsrbar_base + MPC8544_MPIC_REGS_OFFSET + 0xa0;
892e61c36d5SAlexander Graf 
893a34a92b9SAndreas Färber         ppc_booke_timers_init(cpu, 400000000, PPC_TIMER_E500);
8943b989d49SAlexander Graf 
8953b989d49SAlexander Graf         /* Register reset handler */
8965c145dacSAlexander Graf         if (!i) {
8975c145dacSAlexander Graf             /* Primary CPU */
8985c145dacSAlexander Graf             struct boot_info *boot_info;
899e61c36d5SAlexander Graf             boot_info = g_malloc0(sizeof(struct boot_info));
900b3305981SScott Wood             qemu_register_reset(ppce500_cpu_reset, cpu);
901e61c36d5SAlexander Graf             env->load_info = boot_info;
9025c145dacSAlexander Graf         } else {
9035c145dacSAlexander Graf             /* Secondary CPUs */
904b3305981SScott Wood             qemu_register_reset(ppce500_cpu_reset_sec, cpu);
9055c145dacSAlexander Graf         }
906e61c36d5SAlexander Graf     }
907e61c36d5SAlexander Graf 
908e61c36d5SAlexander Graf     env = firstenv;
9093b989d49SAlexander Graf 
9103538e846SIgor Mammedov     if (!QEMU_IS_ALIGNED(machine->ram_size, RAM_SIZES_ALIGN)) {
9113538e846SIgor Mammedov         error_report("RAM size must be multiple of %" PRIu64, RAM_SIZES_ALIGN);
9123538e846SIgor Mammedov         exit(EXIT_FAILURE);
9133538e846SIgor Mammedov     }
9141db09b84Saurel32 
9151db09b84Saurel32     /* Register Memory */
91697316645SIgor Mammedov     memory_region_add_subregion(address_space_mem, 0, machine->ram);
9171db09b84Saurel32 
9183e80f690SMarkus Armbruster     dev = qdev_new("e500-ccsr");
9193eddc1beSBharat Bhushan     object_property_add_child(qdev_get_machine(), "e500-ccsr",
920d2623129SMarkus Armbruster                               OBJECT(dev));
9213c6ef471SMarkus Armbruster     sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
9223eddc1beSBharat Bhushan     ccsr = CCSR(dev);
9233eddc1beSBharat Bhushan     ccsr_addr_space = &ccsr->ccsr_space;
92403f04809SIgor Mammedov     memory_region_add_subregion(address_space_mem, pmc->ccsrbar_base,
9253eddc1beSBharat Bhushan                                 ccsr_addr_space);
926dffb1dc2SBharat Bhushan 
92703f04809SIgor Mammedov     mpicdev = ppce500_init_mpic(pms, ccsr_addr_space, irqs);
9281db09b84Saurel32 
9291db09b84Saurel32     /* Serial */
9309bca0edbSPeter Maydell     if (serial_hd(0)) {
9313eddc1beSBharat Bhushan         serial_mm_init(ccsr_addr_space, MPC8544_SERIAL0_REGS_OFFSET,
932c91c187fSMichael Davidsaver                        0, qdev_get_gpio_in(mpicdev, 42), 399193,
9339bca0edbSPeter Maydell                        serial_hd(0), DEVICE_BIG_ENDIAN);
9342d48377aSBlue Swirl     }
9351db09b84Saurel32 
9369bca0edbSPeter Maydell     if (serial_hd(1)) {
9373eddc1beSBharat Bhushan         serial_mm_init(ccsr_addr_space, MPC8544_SERIAL1_REGS_OFFSET,
938c91c187fSMichael Davidsaver                        0, qdev_get_gpio_in(mpicdev, 42), 399193,
9399bca0edbSPeter Maydell                        serial_hd(1), DEVICE_BIG_ENDIAN);
9402d48377aSBlue Swirl     }
9417abb479cSAndrew Randrianasulu         /* I2C */
9423e80f690SMarkus Armbruster     dev = qdev_new("mpc-i2c");
9437abb479cSAndrew Randrianasulu     s = SYS_BUS_DEVICE(dev);
9443c6ef471SMarkus Armbruster     sysbus_realize_and_unref(s, &error_fatal);
9457abb479cSAndrew Randrianasulu     sysbus_connect_irq(s, 0, qdev_get_gpio_in(mpicdev, MPC8544_I2C_IRQ));
9467abb479cSAndrew Randrianasulu     memory_region_add_subregion(ccsr_addr_space, MPC8544_I2C_REGS_OFFSET,
9477abb479cSAndrew Randrianasulu                                 sysbus_mmio_get_region(s, 0));
9487abb479cSAndrew Randrianasulu     i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c");
9491373b15bSPhilippe Mathieu-Daudé     i2c_slave_create_simple(i2c, "ds1338", RTC_REGS_OFFSET);
9507abb479cSAndrew Randrianasulu 
9511db09b84Saurel32 
952b0fb8423SAlexander Graf     /* General Utility device */
9533e80f690SMarkus Armbruster     dev = qdev_new("mpc8544-guts");
954dffb1dc2SBharat Bhushan     s = SYS_BUS_DEVICE(dev);
9553c6ef471SMarkus Armbruster     sysbus_realize_and_unref(s, &error_fatal);
9563eddc1beSBharat Bhushan     memory_region_add_subregion(ccsr_addr_space, MPC8544_UTIL_OFFSET,
957dffb1dc2SBharat Bhushan                                 sysbus_mmio_get_region(s, 0));
958b0fb8423SAlexander Graf 
9591db09b84Saurel32     /* PCI */
9603e80f690SMarkus Armbruster     dev = qdev_new("e500-pcihost");
961d2623129SMarkus Armbruster     object_property_add_child(qdev_get_machine(), "pci-host", OBJECT(dev));
96203f04809SIgor Mammedov     qdev_prop_set_uint32(dev, "first_slot", pmc->pci_first_slot);
9633016dca0SBharat Bhushan     qdev_prop_set_uint32(dev, "first_pin_irq", pci_irq_nrs[0]);
964dffb1dc2SBharat Bhushan     s = SYS_BUS_DEVICE(dev);
9653c6ef471SMarkus Armbruster     sysbus_realize_and_unref(s, &error_fatal);
966d575a6ceSBharat Bhushan     for (i = 0; i < PCI_NUM_PINS; i++) {
967c91c187fSMichael Davidsaver         sysbus_connect_irq(s, i, qdev_get_gpio_in(mpicdev, pci_irq_nrs[i]));
968d575a6ceSBharat Bhushan     }
969d575a6ceSBharat Bhushan 
9703eddc1beSBharat Bhushan     memory_region_add_subregion(ccsr_addr_space, MPC8544_PCI_REGS_OFFSET,
971dffb1dc2SBharat Bhushan                                 sysbus_mmio_get_region(s, 0));
972dffb1dc2SBharat Bhushan 
973d461e3b9SAlexander Graf     pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
9741db09b84Saurel32     if (!pci_bus)
9751db09b84Saurel32         printf("couldn't create PCI controller!\n");
9761db09b84Saurel32 
9771db09b84Saurel32     if (pci_bus) {
9781db09b84Saurel32         /* Register network interfaces. */
9791db09b84Saurel32         for (i = 0; i < nb_nics; i++) {
98052310c3fSPaolo Bonzini             pci_nic_init_nofail(&nd_table[i], pci_bus, "virtio-net-pci", NULL);
9811db09b84Saurel32         }
9821db09b84Saurel32     }
9831db09b84Saurel32 
9845c145dacSAlexander Graf     /* Register spinning region */
98503f04809SIgor Mammedov     sysbus_create_simple("e500-spin", pmc->spin_base, NULL);
9865c145dacSAlexander Graf 
98703f04809SIgor Mammedov     if (pmc->has_mpc8xxx_gpio) {
988016f7758SAlexander Graf         qemu_irq poweroff_irq;
989016f7758SAlexander Graf 
9903e80f690SMarkus Armbruster         dev = qdev_new("mpc8xxx_gpio");
991b88e77f4SAlexander Graf         s = SYS_BUS_DEVICE(dev);
9923c6ef471SMarkus Armbruster         sysbus_realize_and_unref(s, &error_fatal);
993c91c187fSMichael Davidsaver         sysbus_connect_irq(s, 0, qdev_get_gpio_in(mpicdev, MPC8XXX_GPIO_IRQ));
994b88e77f4SAlexander Graf         memory_region_add_subregion(ccsr_addr_space, MPC8XXX_GPIO_OFFSET,
995b88e77f4SAlexander Graf                                     sysbus_mmio_get_region(s, 0));
996016f7758SAlexander Graf 
997016f7758SAlexander Graf         /* Power Off GPIO at Pin 0 */
998016f7758SAlexander Graf         poweroff_irq = qemu_allocate_irq(ppce500_power_off, NULL, 0);
999016f7758SAlexander Graf         qdev_connect_gpio_out(dev, 0, poweroff_irq);
1000b88e77f4SAlexander Graf     }
1001b88e77f4SAlexander Graf 
1002f7087343SAlexander Graf     /* Platform Bus Device */
100303f04809SIgor Mammedov     if (pmc->has_platform_bus) {
10043e80f690SMarkus Armbruster         dev = qdev_new(TYPE_PLATFORM_BUS_DEVICE);
1005f7087343SAlexander Graf         dev->id = TYPE_PLATFORM_BUS_DEVICE;
100603f04809SIgor Mammedov         qdev_prop_set_uint32(dev, "num_irqs", pmc->platform_bus_num_irqs);
100703f04809SIgor Mammedov         qdev_prop_set_uint32(dev, "mmio_size", pmc->platform_bus_size);
10083c6ef471SMarkus Armbruster         sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
1009a3fc8396SIgor Mammedov         pms->pbus_dev = PLATFORM_BUS_DEVICE(dev);
1010f7087343SAlexander Graf 
1011a3fc8396SIgor Mammedov         s = SYS_BUS_DEVICE(pms->pbus_dev);
101203f04809SIgor Mammedov         for (i = 0; i < pmc->platform_bus_num_irqs; i++) {
101303f04809SIgor Mammedov             int irqn = pmc->platform_bus_first_irq + i;
1014c91c187fSMichael Davidsaver             sysbus_connect_irq(s, i, qdev_get_gpio_in(mpicdev, irqn));
1015f7087343SAlexander Graf         }
1016f7087343SAlexander Graf 
1017f7087343SAlexander Graf         memory_region_add_subregion(address_space_mem,
101803f04809SIgor Mammedov                                     pmc->platform_bus_base,
1019f7087343SAlexander Graf                                     sysbus_mmio_get_region(s, 0));
1020f7087343SAlexander Graf     }
1021f7087343SAlexander Graf 
10228d622594SDavid Engraf     /*
10238d622594SDavid Engraf      * Smart firmware defaults ahead!
10248d622594SDavid Engraf      *
10258d622594SDavid Engraf      * We follow the following table to select which payload we execute.
10268d622594SDavid Engraf      *
10278d622594SDavid Engraf      *  -kernel | -bios | payload
10288d622594SDavid Engraf      * ---------+-------+---------
10298d622594SDavid Engraf      *     N    |   Y   | u-boot
10308d622594SDavid Engraf      *     N    |   N   | u-boot
10318d622594SDavid Engraf      *     Y    |   Y   | u-boot
10328d622594SDavid Engraf      *     Y    |   N   | kernel
10338d622594SDavid Engraf      *
10348d622594SDavid Engraf      * This ensures backwards compatibility with how we used to expose
10358d622594SDavid Engraf      * -kernel to users but allows them to run through u-boot as well.
10368d622594SDavid Engraf      */
10378d622594SDavid Engraf     kernel_as_payload = false;
1038*cd7b9498SPaolo Bonzini     if (machine->firmware == NULL) {
10393ef96221SMarcel Apfelbaum         if (machine->kernel_filename) {
10408d622594SDavid Engraf             payload_name = machine->kernel_filename;
10418d622594SDavid Engraf             kernel_as_payload = true;
10428d622594SDavid Engraf         } else {
10438d622594SDavid Engraf             payload_name = "u-boot.e500";
10448d622594SDavid Engraf         }
10458d622594SDavid Engraf     } else {
1046*cd7b9498SPaolo Bonzini         payload_name = machine->firmware;
10478d622594SDavid Engraf     }
10488d622594SDavid Engraf 
10498d622594SDavid Engraf     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, payload_name);
10503b4f50bdSPeter Maydell     if (!filename) {
10513b4f50bdSPeter Maydell         error_report("could not find firmware/kernel file '%s'", payload_name);
10523b4f50bdSPeter Maydell         exit(1);
10533b4f50bdSPeter Maydell     }
10548d622594SDavid Engraf 
10554366e1dbSLiam Merwick     payload_size = load_elf(filename, NULL, NULL, NULL,
10566cdda0ffSAleksandar Markovic                             &bios_entry, &loadaddr, NULL, NULL,
10578d622594SDavid Engraf                             1, PPC_ELF_MACHINE, 0, 0);
10588d622594SDavid Engraf     if (payload_size < 0) {
10598d622594SDavid Engraf         /*
10608d622594SDavid Engraf          * Hrm. No ELF image? Try a uImage, maybe someone is giving us an
10618d622594SDavid Engraf          * ePAPR compliant kernel
10628d622594SDavid Engraf          */
1063f831f955SNick Hudson         loadaddr = LOAD_UIMAGE_LOADADDR_INVALID;
10648d622594SDavid Engraf         payload_size = load_uimage(filename, &bios_entry, &loadaddr, NULL,
10658d622594SDavid Engraf                                    NULL, NULL);
10668d622594SDavid Engraf         if (payload_size < 0) {
1067371b74e2SMao Zhongyi             error_report("could not load firmware '%s'", filename);
10688d622594SDavid Engraf             exit(1);
10698d622594SDavid Engraf         }
10708d622594SDavid Engraf     }
10718d622594SDavid Engraf 
10728d622594SDavid Engraf     g_free(filename);
10738d622594SDavid Engraf 
10748d622594SDavid Engraf     if (kernel_as_payload) {
10758d622594SDavid Engraf         kernel_base = loadaddr;
10768d622594SDavid Engraf         kernel_size = payload_size;
10778d622594SDavid Engraf     }
10788d622594SDavid Engraf 
10798d622594SDavid Engraf     cur_base = loadaddr + payload_size;
1080ab3dd749SPhilippe Mathieu-Daudé     if (cur_base < 32 * MiB) {
1081b4a5f24aSDavid Engraf         /* u-boot occupies memory up to 32MB, so load blobs above */
1082ab3dd749SPhilippe Mathieu-Daudé         cur_base = 32 * MiB;
1083b4a5f24aSDavid Engraf     }
10848d622594SDavid Engraf 
10858d622594SDavid Engraf     /* Load bare kernel only if no bios/u-boot has been provided */
10868d622594SDavid Engraf     if (machine->kernel_filename && !kernel_as_payload) {
10873812c71fSAlexander Graf         kernel_base = cur_base;
10883812c71fSAlexander Graf         kernel_size = load_image_targphys(machine->kernel_filename,
10893812c71fSAlexander Graf                                           cur_base,
10903538e846SIgor Mammedov                                           machine->ram_size - cur_base);
10911db09b84Saurel32         if (kernel_size < 0) {
10926f76b817SAlistair Francis             error_report("could not load kernel '%s'",
10933ef96221SMarcel Apfelbaum                          machine->kernel_filename);
10941db09b84Saurel32             exit(1);
10951db09b84Saurel32         }
1096528e536eSAlexander Graf 
10973812c71fSAlexander Graf         cur_base += kernel_size;
10981db09b84Saurel32     }
10991db09b84Saurel32 
11001db09b84Saurel32     /* Load initrd. */
11013ef96221SMarcel Apfelbaum     if (machine->initrd_filename) {
1102528e536eSAlexander Graf         initrd_base = (cur_base + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK;
11033ef96221SMarcel Apfelbaum         initrd_size = load_image_targphys(machine->initrd_filename, initrd_base,
11043538e846SIgor Mammedov                                           machine->ram_size - initrd_base);
11051db09b84Saurel32 
11061db09b84Saurel32         if (initrd_size < 0) {
11076f76b817SAlistair Francis             error_report("could not load initial ram disk '%s'",
11083ef96221SMarcel Apfelbaum                          machine->initrd_filename);
11091db09b84Saurel32             exit(1);
11101db09b84Saurel32         }
1111528e536eSAlexander Graf 
1112528e536eSAlexander Graf         cur_base = initrd_base + initrd_size;
11131db09b84Saurel32     }
11141db09b84Saurel32 
11153812c71fSAlexander Graf     /*
11168d622594SDavid Engraf      * Reserve space for dtb behind the kernel image because Linux has a bug
11178d622594SDavid Engraf      * where it can only handle the dtb if it's within the first 64MB of where
11188d622594SDavid Engraf      * <kernel> starts. dtb cannot not reach initrd_base because INITRD_LOAD_PAD
11198d622594SDavid Engraf      * ensures enough space between kernel and initrd.
11203812c71fSAlexander Graf      */
11218d622594SDavid Engraf     dt_base = (loadaddr + payload_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
11223538e846SIgor Mammedov     if (dt_base + DTB_MAX_SIZE > machine->ram_size) {
1123371b74e2SMao Zhongyi             error_report("not enough memory for device tree");
11243812c71fSAlexander Graf             exit(1);
11253812c71fSAlexander Graf     }
11265c145dacSAlexander Graf 
112703f04809SIgor Mammedov     dt_size = ppce500_prep_device_tree(pms, dt_base,
1128903585deSAlexander Graf                                        initrd_base, initrd_size,
11293812c71fSAlexander Graf                                        kernel_base, kernel_size);
1130cba2026aSAlexander Graf     if (dt_size < 0) {
11316f76b817SAlistair Francis         error_report("couldn't load device tree");
11321db09b84Saurel32         exit(1);
11331db09b84Saurel32     }
1134b8dec144SAlexander Graf     assert(dt_size < DTB_MAX_SIZE);
11351db09b84Saurel32 
1136e61c36d5SAlexander Graf     boot_info = env->load_info;
11373812c71fSAlexander Graf     boot_info->entry = bios_entry;
11383b989d49SAlexander Graf     boot_info->dt_base = dt_base;
1139cba2026aSAlexander Graf     boot_info->dt_size = dt_size;
11401db09b84Saurel32 }
11413eddc1beSBharat Bhushan 
1142d0c2b0d0Sxiaoqiang zhao static void e500_ccsr_initfn(Object *obj)
11433eddc1beSBharat Bhushan {
1144d0c2b0d0Sxiaoqiang zhao     PPCE500CCSRState *ccsr = CCSR(obj);
1145d0c2b0d0Sxiaoqiang zhao     memory_region_init(&ccsr->ccsr_space, obj, "e500-ccsr",
11463eddc1beSBharat Bhushan                        MPC8544_CCSRBAR_SIZE);
11473eddc1beSBharat Bhushan }
11483eddc1beSBharat Bhushan 
11493eddc1beSBharat Bhushan static const TypeInfo e500_ccsr_info = {
11503eddc1beSBharat Bhushan     .name          = TYPE_CCSR,
11513eddc1beSBharat Bhushan     .parent        = TYPE_SYS_BUS_DEVICE,
11523eddc1beSBharat Bhushan     .instance_size = sizeof(PPCE500CCSRState),
1153d0c2b0d0Sxiaoqiang zhao     .instance_init = e500_ccsr_initfn,
11543eddc1beSBharat Bhushan };
11553eddc1beSBharat Bhushan 
115603f04809SIgor Mammedov static const TypeInfo ppce500_info = {
115703f04809SIgor Mammedov     .name          = TYPE_PPCE500_MACHINE,
115803f04809SIgor Mammedov     .parent        = TYPE_MACHINE,
115903f04809SIgor Mammedov     .abstract      = true,
1160a3fc8396SIgor Mammedov     .instance_size = sizeof(PPCE500MachineState),
116103f04809SIgor Mammedov     .class_size    = sizeof(PPCE500MachineClass),
116203f04809SIgor Mammedov };
116303f04809SIgor Mammedov 
11643eddc1beSBharat Bhushan static void e500_register_types(void)
11653eddc1beSBharat Bhushan {
11663eddc1beSBharat Bhushan     type_register_static(&e500_ccsr_info);
116703f04809SIgor Mammedov     type_register_static(&ppce500_info);
11683eddc1beSBharat Bhushan }
11693eddc1beSBharat Bhushan 
11703eddc1beSBharat Bhushan type_init(e500_register_types)
1171