xref: /qemu/hw/ppc/e500.c (revision a27bd6c779badb8d76e4430d810ef710a1b98f4e)
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"
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"
36*a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
374a18e7c9SScott Wood #include "hw/loader.h"
38ca20cf32SBlue Swirl #include "elf.h"
394a18e7c9SScott Wood #include "hw/sysbus.h"
40022c62cbSPaolo Bonzini #include "exec/address-spaces.h"
411de7afc9SPaolo Bonzini #include "qemu/host-utils.h"
42922a01a0SMarkus Armbruster #include "qemu/option.h"
430d09e41aSPaolo Bonzini #include "hw/pci-host/ppce500.h"
44f7087343SAlexander Graf #include "qemu/error-report.h"
45f7087343SAlexander Graf #include "hw/platform-bus.h"
46fdfb7f2cSAlexander Graf #include "hw/net/fsl_etsec/etsec.h"
477abb479cSAndrew Randrianasulu #include "hw/i2c/i2c.h"
4864552b6bSMarkus Armbruster #include "hw/irq.h"
491db09b84Saurel32 
50cefd3cdbSBharat Bhushan #define EPAPR_MAGIC                (0x45504150)
511db09b84Saurel32 #define BINARY_DEVICE_TREE_FILE    "mpc8544ds.dtb"
529dd5eba1SScott Wood #define DTC_LOAD_PAD               0x1800000
5375bb6589SLiu Yu #define DTC_PAD_MASK               0xFFFFF
54ab3dd749SPhilippe Mathieu-Daudé #define DTB_MAX_SIZE               (8 * MiB)
5575bb6589SLiu Yu #define INITRD_LOAD_PAD            0x2000000
5675bb6589SLiu Yu #define INITRD_PAD_MASK            0xFFFFFF
571db09b84Saurel32 
58ab3dd749SPhilippe Mathieu-Daudé #define RAM_SIZES_ALIGN            (64 * MiB)
591db09b84Saurel32 
60b3305981SScott Wood /* TODO: parameterize */
61ed2bc496SAlexander Graf #define MPC8544_CCSRBAR_SIZE       0x00100000ULL
62dffb1dc2SBharat Bhushan #define MPC8544_MPIC_REGS_OFFSET   0x40000ULL
63a911b7a9SAlexander Graf #define MPC8544_MSI_REGS_OFFSET   0x41600ULL
64dffb1dc2SBharat Bhushan #define MPC8544_SERIAL0_REGS_OFFSET 0x4500ULL
65dffb1dc2SBharat Bhushan #define MPC8544_SERIAL1_REGS_OFFSET 0x4600ULL
66dffb1dc2SBharat Bhushan #define MPC8544_PCI_REGS_OFFSET    0x8000ULL
67ed2bc496SAlexander Graf #define MPC8544_PCI_REGS_SIZE      0x1000ULL
68dffb1dc2SBharat Bhushan #define MPC8544_UTIL_OFFSET        0xe0000ULL
69b88e77f4SAlexander Graf #define MPC8XXX_GPIO_OFFSET        0x000FF000ULL
707abb479cSAndrew Randrianasulu #define MPC8544_I2C_REGS_OFFSET    0x3000ULL
7182e345f5SAmit Tomar #define MPC8XXX_GPIO_IRQ           47
727abb479cSAndrew Randrianasulu #define MPC8544_I2C_IRQ            43
737abb479cSAndrew Randrianasulu #define RTC_REGS_OFFSET            0x68
741db09b84Saurel32 
753b989d49SAlexander Graf struct boot_info
763b989d49SAlexander Graf {
773b989d49SAlexander Graf     uint32_t dt_base;
78cba2026aSAlexander Graf     uint32_t dt_size;
793b989d49SAlexander Graf     uint32_t entry;
803b989d49SAlexander Graf };
813b989d49SAlexander Graf 
82347dd79dSAlexander Graf static uint32_t *pci_map_create(void *fdt, uint32_t mpic, int first_slot,
83347dd79dSAlexander Graf                                 int nr_slots, int *len)
840dbc0798SAlexander Graf {
85347dd79dSAlexander Graf     int i = 0;
86347dd79dSAlexander Graf     int slot;
87347dd79dSAlexander Graf     int pci_irq;
889e2c1298SAlexander Graf     int host_irq;
89347dd79dSAlexander Graf     int last_slot = first_slot + nr_slots;
90347dd79dSAlexander Graf     uint32_t *pci_map;
910dbc0798SAlexander Graf 
92347dd79dSAlexander Graf     *len = nr_slots * 4 * 7 * sizeof(uint32_t);
93347dd79dSAlexander Graf     pci_map = g_malloc(*len);
94347dd79dSAlexander Graf 
95347dd79dSAlexander Graf     for (slot = first_slot; slot < last_slot; slot++) {
96347dd79dSAlexander Graf         for (pci_irq = 0; pci_irq < 4; pci_irq++) {
97347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(slot << 11);
98347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(0x0);
99347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(0x0);
100347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(pci_irq + 1);
101347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(mpic);
1029e2c1298SAlexander Graf             host_irq = ppce500_pci_map_irq_slot(slot, pci_irq);
1039e2c1298SAlexander Graf             pci_map[i++] = cpu_to_be32(host_irq + 1);
104347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(0x1);
1050dbc0798SAlexander Graf         }
1060dbc0798SAlexander Graf     }
1070dbc0798SAlexander Graf 
108347dd79dSAlexander Graf     assert((i * sizeof(uint32_t)) == *len);
109347dd79dSAlexander Graf 
110347dd79dSAlexander Graf     return pci_map;
111347dd79dSAlexander Graf }
112347dd79dSAlexander Graf 
113a053a7ceSAlexander Graf static void dt_serial_create(void *fdt, unsigned long long offset,
114a053a7ceSAlexander Graf                              const char *soc, const char *mpic,
115a053a7ceSAlexander Graf                              const char *alias, int idx, bool defcon)
116a053a7ceSAlexander Graf {
1172fb513d3SGreg Kurz     char *ser;
118a053a7ceSAlexander Graf 
1192fb513d3SGreg Kurz     ser = g_strdup_printf("%s/serial@%llx", soc, offset);
1205a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, ser);
1215a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, ser, "device_type", "serial");
1225a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, ser, "compatible", "ns16550");
1235a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, ser, "reg", offset, 0x100);
1245a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, ser, "cell-index", idx);
1255a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, ser, "clock-frequency", 0);
1265a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, ser, "interrupts", 42, 2);
1275a4348d1SPeter Crosthwaite     qemu_fdt_setprop_phandle(fdt, ser, "interrupt-parent", mpic);
1285a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, "/aliases", alias, ser);
129a053a7ceSAlexander Graf 
130a053a7ceSAlexander Graf     if (defcon) {
13190ee4e01SNikunj A Dadhania         /*
13290ee4e01SNikunj A Dadhania          * "linux,stdout-path" and "stdout" properties are deprecated by linux
13390ee4e01SNikunj A Dadhania          * kernel. New platforms should only use the "stdout-path" property. Set
13490ee4e01SNikunj A Dadhania          * the new property and continue using older property to remain
13590ee4e01SNikunj A Dadhania          * compatible with the existing firmware.
13690ee4e01SNikunj A Dadhania          */
1375a4348d1SPeter Crosthwaite         qemu_fdt_setprop_string(fdt, "/chosen", "linux,stdout-path", ser);
13890ee4e01SNikunj A Dadhania         qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", ser);
139a053a7ceSAlexander Graf     }
1402fb513d3SGreg Kurz     g_free(ser);
141a053a7ceSAlexander Graf }
142a053a7ceSAlexander Graf 
143b88e77f4SAlexander Graf static void create_dt_mpc8xxx_gpio(void *fdt, const char *soc, const char *mpic)
144b88e77f4SAlexander Graf {
145b88e77f4SAlexander Graf     hwaddr mmio0 = MPC8XXX_GPIO_OFFSET;
146b88e77f4SAlexander Graf     int irq0 = MPC8XXX_GPIO_IRQ;
147b88e77f4SAlexander Graf     gchar *node = g_strdup_printf("%s/gpio@%"PRIx64, soc, mmio0);
148016f7758SAlexander Graf     gchar *poweroff = g_strdup_printf("%s/power-off", soc);
149016f7758SAlexander Graf     int gpio_ph;
150b88e77f4SAlexander Graf 
151b88e77f4SAlexander Graf     qemu_fdt_add_subnode(fdt, node);
152b88e77f4SAlexander Graf     qemu_fdt_setprop_string(fdt, node, "compatible", "fsl,qoriq-gpio");
153b88e77f4SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "reg", mmio0, 0x1000);
154b88e77f4SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "interrupts", irq0, 0x2);
155b88e77f4SAlexander Graf     qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", mpic);
156b88e77f4SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "#gpio-cells", 2);
157b88e77f4SAlexander Graf     qemu_fdt_setprop(fdt, node, "gpio-controller", NULL, 0);
158016f7758SAlexander Graf     gpio_ph = qemu_fdt_alloc_phandle(fdt);
159016f7758SAlexander Graf     qemu_fdt_setprop_cell(fdt, node, "phandle", gpio_ph);
160016f7758SAlexander Graf     qemu_fdt_setprop_cell(fdt, node, "linux,phandle", gpio_ph);
161016f7758SAlexander Graf 
162016f7758SAlexander Graf     /* Power Off Pin */
163016f7758SAlexander Graf     qemu_fdt_add_subnode(fdt, poweroff);
164016f7758SAlexander Graf     qemu_fdt_setprop_string(fdt, poweroff, "compatible", "gpio-poweroff");
165016f7758SAlexander Graf     qemu_fdt_setprop_cells(fdt, poweroff, "gpios", gpio_ph, 0, 0);
166b88e77f4SAlexander Graf 
167b88e77f4SAlexander Graf     g_free(node);
168016f7758SAlexander Graf     g_free(poweroff);
169b88e77f4SAlexander Graf }
170b88e77f4SAlexander Graf 
1717abb479cSAndrew Randrianasulu static void dt_rtc_create(void *fdt, const char *i2c, const char *alias)
1727abb479cSAndrew Randrianasulu {
1737abb479cSAndrew Randrianasulu     int offset = RTC_REGS_OFFSET;
1747abb479cSAndrew Randrianasulu 
1757abb479cSAndrew Randrianasulu     gchar *rtc = g_strdup_printf("%s/rtc@%"PRIx32, i2c, offset);
1767abb479cSAndrew Randrianasulu     qemu_fdt_add_subnode(fdt, rtc);
1777abb479cSAndrew Randrianasulu     qemu_fdt_setprop_string(fdt, rtc, "compatible", "pericom,pt7c4338");
1787abb479cSAndrew Randrianasulu     qemu_fdt_setprop_cells(fdt, rtc, "reg", offset);
1797abb479cSAndrew Randrianasulu     qemu_fdt_setprop_string(fdt, "/aliases", alias, rtc);
1807abb479cSAndrew Randrianasulu 
1817abb479cSAndrew Randrianasulu     g_free(rtc);
1827abb479cSAndrew Randrianasulu }
1837abb479cSAndrew Randrianasulu 
1847abb479cSAndrew Randrianasulu static void dt_i2c_create(void *fdt, const char *soc, const char *mpic,
1857abb479cSAndrew Randrianasulu                              const char *alias)
1867abb479cSAndrew Randrianasulu {
1877abb479cSAndrew Randrianasulu     hwaddr mmio0 = MPC8544_I2C_REGS_OFFSET;
1887abb479cSAndrew Randrianasulu     int irq0 = MPC8544_I2C_IRQ;
1897abb479cSAndrew Randrianasulu 
1907abb479cSAndrew Randrianasulu     gchar *i2c = g_strdup_printf("%s/i2c@%"PRIx64, soc, mmio0);
1917abb479cSAndrew Randrianasulu     qemu_fdt_add_subnode(fdt, i2c);
1927abb479cSAndrew Randrianasulu     qemu_fdt_setprop_string(fdt, i2c, "device_type", "i2c");
1937abb479cSAndrew Randrianasulu     qemu_fdt_setprop_string(fdt, i2c, "compatible", "fsl-i2c");
1947abb479cSAndrew Randrianasulu     qemu_fdt_setprop_cells(fdt, i2c, "reg", mmio0, 0x14);
1957abb479cSAndrew Randrianasulu     qemu_fdt_setprop_cells(fdt, i2c, "cell-index", 0);
1967abb479cSAndrew Randrianasulu     qemu_fdt_setprop_cells(fdt, i2c, "interrupts", irq0, 0x2);
1977abb479cSAndrew Randrianasulu     qemu_fdt_setprop_phandle(fdt, i2c, "interrupt-parent", mpic);
1987abb479cSAndrew Randrianasulu     qemu_fdt_setprop_string(fdt, "/aliases", alias, i2c);
1997abb479cSAndrew Randrianasulu 
2007abb479cSAndrew Randrianasulu     g_free(i2c);
2017abb479cSAndrew Randrianasulu }
2027abb479cSAndrew Randrianasulu 
2037abb479cSAndrew Randrianasulu 
204f7087343SAlexander Graf typedef struct PlatformDevtreeData {
205f7087343SAlexander Graf     void *fdt;
206f7087343SAlexander Graf     const char *mpic;
207f7087343SAlexander Graf     int irq_start;
208f7087343SAlexander Graf     const char *node;
209f7087343SAlexander Graf     PlatformBusDevice *pbus;
210f7087343SAlexander Graf } PlatformDevtreeData;
211f7087343SAlexander Graf 
212fdfb7f2cSAlexander Graf static int create_devtree_etsec(SysBusDevice *sbdev, PlatformDevtreeData *data)
213fdfb7f2cSAlexander Graf {
214fdfb7f2cSAlexander Graf     eTSEC *etsec = ETSEC_COMMON(sbdev);
215fdfb7f2cSAlexander Graf     PlatformBusDevice *pbus = data->pbus;
216fdfb7f2cSAlexander Graf     hwaddr mmio0 = platform_bus_get_mmio_addr(pbus, sbdev, 0);
217fdfb7f2cSAlexander Graf     int irq0 = platform_bus_get_irqn(pbus, sbdev, 0);
218fdfb7f2cSAlexander Graf     int irq1 = platform_bus_get_irqn(pbus, sbdev, 1);
219fdfb7f2cSAlexander Graf     int irq2 = platform_bus_get_irqn(pbus, sbdev, 2);
220fdfb7f2cSAlexander Graf     gchar *node = g_strdup_printf("/platform/ethernet@%"PRIx64, mmio0);
221fdfb7f2cSAlexander Graf     gchar *group = g_strdup_printf("%s/queue-group", node);
222fdfb7f2cSAlexander Graf     void *fdt = data->fdt;
223fdfb7f2cSAlexander Graf 
224fdfb7f2cSAlexander Graf     assert((int64_t)mmio0 >= 0);
225fdfb7f2cSAlexander Graf     assert(irq0 >= 0);
226fdfb7f2cSAlexander Graf     assert(irq1 >= 0);
227fdfb7f2cSAlexander Graf     assert(irq2 >= 0);
228fdfb7f2cSAlexander Graf 
229fdfb7f2cSAlexander Graf     qemu_fdt_add_subnode(fdt, node);
230fdfb7f2cSAlexander Graf     qemu_fdt_setprop_string(fdt, node, "device_type", "network");
231fdfb7f2cSAlexander Graf     qemu_fdt_setprop_string(fdt, node, "compatible", "fsl,etsec2");
232fdfb7f2cSAlexander Graf     qemu_fdt_setprop_string(fdt, node, "model", "eTSEC");
233fdfb7f2cSAlexander Graf     qemu_fdt_setprop(fdt, node, "local-mac-address", etsec->conf.macaddr.a, 6);
234fdfb7f2cSAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "fixed-link", 0, 1, 1000, 0, 0);
235fdfb7f2cSAlexander Graf 
236fdfb7f2cSAlexander Graf     qemu_fdt_add_subnode(fdt, group);
237fdfb7f2cSAlexander Graf     qemu_fdt_setprop_cells(fdt, group, "reg", mmio0, 0x1000);
238fdfb7f2cSAlexander Graf     qemu_fdt_setprop_cells(fdt, group, "interrupts",
239fdfb7f2cSAlexander Graf         data->irq_start + irq0, 0x2,
240fdfb7f2cSAlexander Graf         data->irq_start + irq1, 0x2,
241fdfb7f2cSAlexander Graf         data->irq_start + irq2, 0x2);
242fdfb7f2cSAlexander Graf 
243fdfb7f2cSAlexander Graf     g_free(node);
244fdfb7f2cSAlexander Graf     g_free(group);
245fdfb7f2cSAlexander Graf 
246fdfb7f2cSAlexander Graf     return 0;
247fdfb7f2cSAlexander Graf }
248fdfb7f2cSAlexander Graf 
2494f01a637SDavid Gibson static void sysbus_device_create_devtree(SysBusDevice *sbdev, void *opaque)
250f7087343SAlexander Graf {
251f7087343SAlexander Graf     PlatformDevtreeData *data = opaque;
252f7087343SAlexander Graf     bool matched = false;
253f7087343SAlexander Graf 
254fdfb7f2cSAlexander Graf     if (object_dynamic_cast(OBJECT(sbdev), TYPE_ETSEC_COMMON)) {
255fdfb7f2cSAlexander Graf         create_devtree_etsec(sbdev, data);
256fdfb7f2cSAlexander Graf         matched = true;
257fdfb7f2cSAlexander Graf     }
258fdfb7f2cSAlexander Graf 
259f7087343SAlexander Graf     if (!matched) {
260f7087343SAlexander Graf         error_report("Device %s is not supported by this machine yet.",
261f7087343SAlexander Graf                      qdev_fw_name(DEVICE(sbdev)));
262f7087343SAlexander Graf         exit(1);
263f7087343SAlexander Graf     }
264f7087343SAlexander Graf }
265f7087343SAlexander Graf 
266a3fc8396SIgor Mammedov static void platform_bus_create_devtree(PPCE500MachineState *pms,
26703f04809SIgor Mammedov                                         void *fdt, const char *mpic)
268f7087343SAlexander Graf {
269a3fc8396SIgor Mammedov     const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(pms);
27003f04809SIgor Mammedov     gchar *node = g_strdup_printf("/platform@%"PRIx64, pmc->platform_bus_base);
271f7087343SAlexander Graf     const char platcomp[] = "qemu,platform\0simple-bus";
27203f04809SIgor Mammedov     uint64_t addr = pmc->platform_bus_base;
27303f04809SIgor Mammedov     uint64_t size = pmc->platform_bus_size;
27403f04809SIgor Mammedov     int irq_start = pmc->platform_bus_first_irq;
275f7087343SAlexander Graf 
276f7087343SAlexander Graf     /* Create a /platform node that we can put all devices into */
277f7087343SAlexander Graf 
278f7087343SAlexander Graf     qemu_fdt_add_subnode(fdt, node);
279f7087343SAlexander Graf     qemu_fdt_setprop(fdt, node, "compatible", platcomp, sizeof(platcomp));
280f7087343SAlexander Graf 
281f7087343SAlexander Graf     /* Our platform bus region is less than 32bit big, so 1 cell is enough for
282f7087343SAlexander Graf        address and size */
283f7087343SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "#size-cells", 1);
284f7087343SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "#address-cells", 1);
285f7087343SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "ranges", 0, addr >> 32, addr, size);
286f7087343SAlexander Graf 
287f7087343SAlexander Graf     qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", mpic);
288f7087343SAlexander Graf 
289a3fc8396SIgor Mammedov     /* Create dt nodes for dynamic devices */
290f7087343SAlexander Graf     PlatformDevtreeData data = {
291f7087343SAlexander Graf         .fdt = fdt,
292f7087343SAlexander Graf         .mpic = mpic,
293f7087343SAlexander Graf         .irq_start = irq_start,
294f7087343SAlexander Graf         .node = node,
295a3fc8396SIgor Mammedov         .pbus = pms->pbus_dev,
296f7087343SAlexander Graf     };
297f7087343SAlexander Graf 
298f7087343SAlexander Graf     /* Loop through all dynamic sysbus devices and create nodes for them */
299f7087343SAlexander Graf     foreach_dynamic_sysbus_device(sysbus_device_create_devtree, &data);
300f7087343SAlexander Graf 
301f7087343SAlexander Graf     g_free(node);
302f7087343SAlexander Graf }
303f7087343SAlexander Graf 
30403f04809SIgor Mammedov static int ppce500_load_device_tree(PPCE500MachineState *pms,
305a8170e5eSAvi Kivity                                     hwaddr addr,
306a8170e5eSAvi Kivity                                     hwaddr initrd_base,
30728290f37SAlexander Graf                                     hwaddr initrd_size,
308903585deSAlexander Graf                                     hwaddr kernel_base,
309903585deSAlexander Graf                                     hwaddr kernel_size,
31028290f37SAlexander Graf                                     bool dry_run)
3111db09b84Saurel32 {
31203f04809SIgor Mammedov     MachineState *machine = MACHINE(pms);
313fe6b6346SLike Xu     unsigned int smp_cpus = machine->smp.cpus;
31403f04809SIgor Mammedov     const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(pms);
31528290f37SAlexander Graf     CPUPPCState *env = first_cpu->env_ptr;
316dbf916d8SAurelien Jarno     int ret = -1;
3173ef96221SMarcel Apfelbaum     uint64_t mem_reg_property[] = { 0, cpu_to_be64(machine->ram_size) };
3187ec632b4Spbrook     int fdt_size;
319dbf916d8SAurelien Jarno     void *fdt;
3205de6b46dSAlexander Graf     uint8_t hypercall[16];
321911d6e7aSAlexander Graf     uint32_t clock_freq = 400000000;
322911d6e7aSAlexander Graf     uint32_t tb_freq = 400000000;
323621d05e3SAlexander Graf     int i;
324ebb9518aSAlexander Graf     char compatible_sb[] = "fsl,mpc8544-immr\0simple-bus";
3252fb513d3SGreg Kurz     char *soc;
3262fb513d3SGreg Kurz     char *mpic;
32719ac9deaSAlexander Graf     uint32_t mpic_ph;
328a911b7a9SAlexander Graf     uint32_t msi_ph;
3292fb513d3SGreg Kurz     char *gutil;
3302fb513d3SGreg Kurz     char *pci;
3312fb513d3SGreg Kurz     char *msi;
332347dd79dSAlexander Graf     uint32_t *pci_map = NULL;
333347dd79dSAlexander Graf     int len;
3343627757eSAlexander Graf     uint32_t pci_ranges[14] =
3353627757eSAlexander Graf         {
33603f04809SIgor Mammedov             0x2000000, 0x0, pmc->pci_mmio_bus_base,
33703f04809SIgor Mammedov             pmc->pci_mmio_base >> 32, pmc->pci_mmio_base,
3383627757eSAlexander Graf             0x0, 0x20000000,
3393627757eSAlexander Graf 
3403627757eSAlexander Graf             0x1000000, 0x0, 0x0,
34103f04809SIgor Mammedov             pmc->pci_pio_base >> 32, pmc->pci_pio_base,
3423627757eSAlexander Graf             0x0, 0x10000,
3433627757eSAlexander Graf         };
3442ff3de68SMarkus Armbruster     QemuOpts *machine_opts = qemu_get_machine_opts();
3452ff3de68SMarkus Armbruster     const char *dtb_file = qemu_opt_get(machine_opts, "dtb");
3462ff3de68SMarkus Armbruster     const char *toplevel_compat = qemu_opt_get(machine_opts, "dt_compatible");
347d1b93565SAlexander Graf 
348d1b93565SAlexander Graf     if (dtb_file) {
349d1b93565SAlexander Graf         char *filename;
350d1b93565SAlexander Graf         filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_file);
351d1b93565SAlexander Graf         if (!filename) {
352d1b93565SAlexander Graf             goto out;
353d1b93565SAlexander Graf         }
354d1b93565SAlexander Graf 
355d1b93565SAlexander Graf         fdt = load_device_tree(filename, &fdt_size);
3562343dd11SMichael Tokarev         g_free(filename);
357d1b93565SAlexander Graf         if (!fdt) {
358d1b93565SAlexander Graf             goto out;
359d1b93565SAlexander Graf         }
360d1b93565SAlexander Graf         goto done;
361d1b93565SAlexander Graf     }
3621db09b84Saurel32 
3632636fcb6SAlexander Graf     fdt = create_device_tree(&fdt_size);
3645cea8590SPaul Brook     if (fdt == NULL) {
3655cea8590SPaul Brook         goto out;
3665cea8590SPaul Brook     }
3671db09b84Saurel32 
3681db09b84Saurel32     /* Manipulate device tree in memory. */
3695a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 2);
3705a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 2);
37151b852b7SAlexander Graf 
3725a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, "/memory");
3735a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, "/memory", "device_type", "memory");
3745a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, "/memory", "reg", mem_reg_property,
3751db09b84Saurel32                      sizeof(mem_reg_property));
3761db09b84Saurel32 
3775a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, "/chosen");
3783b989d49SAlexander Graf     if (initrd_size) {
3795a4348d1SPeter Crosthwaite         ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start",
3801db09b84Saurel32                                     initrd_base);
3813b989d49SAlexander Graf         if (ret < 0) {
3821db09b84Saurel32             fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
3833b989d49SAlexander Graf         }
3841db09b84Saurel32 
3855a4348d1SPeter Crosthwaite         ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
3861db09b84Saurel32                                     (initrd_base + initrd_size));
3873b989d49SAlexander Graf         if (ret < 0) {
3881db09b84Saurel32             fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
3893b989d49SAlexander Graf         }
390903585deSAlexander Graf 
391903585deSAlexander Graf     }
392903585deSAlexander Graf 
393903585deSAlexander Graf     if (kernel_base != -1ULL) {
394903585deSAlexander Graf         qemu_fdt_setprop_cells(fdt, "/chosen", "qemu,boot-kernel",
395903585deSAlexander Graf                                      kernel_base >> 32, kernel_base,
396903585deSAlexander Graf                                      kernel_size >> 32, kernel_size);
3973b989d49SAlexander Graf     }
3981db09b84Saurel32 
3995a4348d1SPeter Crosthwaite     ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
4003ef96221SMarcel Apfelbaum                                       machine->kernel_cmdline);
4011db09b84Saurel32     if (ret < 0)
4021db09b84Saurel32         fprintf(stderr, "couldn't set /chosen/bootargs\n");
4031db09b84Saurel32 
4041db09b84Saurel32     if (kvm_enabled()) {
405911d6e7aSAlexander Graf         /* Read out host's frequencies */
406911d6e7aSAlexander Graf         clock_freq = kvmppc_get_clockfreq();
407911d6e7aSAlexander Graf         tb_freq = kvmppc_get_tbfreq();
4085de6b46dSAlexander Graf 
4095de6b46dSAlexander Graf         /* indicate KVM hypercall interface */
4105a4348d1SPeter Crosthwaite         qemu_fdt_add_subnode(fdt, "/hypervisor");
4115a4348d1SPeter Crosthwaite         qemu_fdt_setprop_string(fdt, "/hypervisor", "compatible",
4125de6b46dSAlexander Graf                                 "linux,kvm");
4135de6b46dSAlexander Graf         kvmppc_get_hypercall(env, hypercall, sizeof(hypercall));
4145a4348d1SPeter Crosthwaite         qemu_fdt_setprop(fdt, "/hypervisor", "hcall-instructions",
4155de6b46dSAlexander Graf                          hypercall, sizeof(hypercall));
4161a61a9aeSStuart Yoder         /* if KVM supports the idle hcall, set property indicating this */
4171a61a9aeSStuart Yoder         if (kvmppc_get_hasidle(env)) {
4185a4348d1SPeter Crosthwaite             qemu_fdt_setprop(fdt, "/hypervisor", "has-idle", NULL, 0);
4191a61a9aeSStuart Yoder         }
4201db09b84Saurel32     }
4211db09b84Saurel32 
422625e665bSAlexander Graf     /* Create CPU nodes */
4235a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, "/cpus");
4245a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 1);
4255a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0);
426625e665bSAlexander Graf 
4271e3debf0SAlexander Graf     /* We need to generate the cpu nodes in reverse order, so Linux can pick
4281e3debf0SAlexander Graf        the first node as boot node and be happy */
4291e3debf0SAlexander Graf     for (i = smp_cpus - 1; i >= 0; i--) {
430440c8152SAndreas Färber         CPUState *cpu;
4312fb513d3SGreg Kurz         char *cpu_name;
43203f04809SIgor Mammedov         uint64_t cpu_release_addr = pmc->spin_base + (i * 0x20);
43310f25a46SAlexander Graf 
434440c8152SAndreas Färber         cpu = qemu_get_cpu(i);
43555e5c285SAndreas Färber         if (cpu == NULL) {
4361e3debf0SAlexander Graf             continue;
4371e3debf0SAlexander Graf         }
438440c8152SAndreas Färber         env = cpu->env_ptr;
4391e3debf0SAlexander Graf 
4402fb513d3SGreg Kurz         cpu_name = g_strdup_printf("/cpus/PowerPC,8544@%x", i);
4415a4348d1SPeter Crosthwaite         qemu_fdt_add_subnode(fdt, cpu_name);
4425a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq);
4435a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq);
4445a4348d1SPeter Crosthwaite         qemu_fdt_setprop_string(fdt, cpu_name, "device_type", "cpu");
4456d536570SSam Bobroff         qemu_fdt_setprop_cell(fdt, cpu_name, "reg", i);
4465a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-line-size",
4471e3debf0SAlexander Graf                               env->dcache_line_size);
4485a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-line-size",
4491e3debf0SAlexander Graf                               env->icache_line_size);
4505a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-size", 0x8000);
4515a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-size", 0x8000);
4525a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "bus-frequency", 0);
45355e5c285SAndreas Färber         if (cpu->cpu_index) {
4545a4348d1SPeter Crosthwaite             qemu_fdt_setprop_string(fdt, cpu_name, "status", "disabled");
4555a4348d1SPeter Crosthwaite             qemu_fdt_setprop_string(fdt, cpu_name, "enable-method",
4565a4348d1SPeter Crosthwaite                                     "spin-table");
4575a4348d1SPeter Crosthwaite             qemu_fdt_setprop_u64(fdt, cpu_name, "cpu-release-addr",
4581d2e5c52SAlexander Graf                                  cpu_release_addr);
4591e3debf0SAlexander Graf         } else {
4605a4348d1SPeter Crosthwaite             qemu_fdt_setprop_string(fdt, cpu_name, "status", "okay");
4611e3debf0SAlexander Graf         }
4622fb513d3SGreg Kurz         g_free(cpu_name);
4631db09b84Saurel32     }
4641db09b84Saurel32 
4655a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, "/aliases");
4665da96624SAlexander Graf     /* XXX These should go into their respective devices' code */
4672fb513d3SGreg Kurz     soc = g_strdup_printf("/soc@%"PRIx64, pmc->ccsrbar_base);
4685a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, soc);
4695a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, soc, "device_type", "soc");
4705a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, soc, "compatible", compatible_sb,
471ebb9518aSAlexander Graf                      sizeof(compatible_sb));
4725a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, soc, "#address-cells", 1);
4735a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, soc, "#size-cells", 1);
4745a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, soc, "ranges", 0x0,
47503f04809SIgor Mammedov                            pmc->ccsrbar_base >> 32, pmc->ccsrbar_base,
4765da96624SAlexander Graf                            MPC8544_CCSRBAR_SIZE);
4775da96624SAlexander Graf     /* XXX should contain a reasonable value */
4785a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, soc, "bus-frequency", 0);
4795da96624SAlexander Graf 
4802fb513d3SGreg Kurz     mpic = g_strdup_printf("%s/pic@%llx", soc, MPC8544_MPIC_REGS_OFFSET);
4815a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, mpic);
4825a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, mpic, "device_type", "open-pic");
4835a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, mpic, "compatible", "fsl,mpic");
4845a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_OFFSET,
485dffb1dc2SBharat Bhushan                            0x40000);
4865a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, mpic, "#address-cells", 0);
4875a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, mpic, "#interrupt-cells", 2);
4885a4348d1SPeter Crosthwaite     mpic_ph = qemu_fdt_alloc_phandle(fdt);
4895a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, mpic, "phandle", mpic_ph);
4905a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, mpic, "linux,phandle", mpic_ph);
4915a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, mpic, "interrupt-controller", NULL, 0);
49219ac9deaSAlexander Graf 
4930cfc6e8dSAlexander Graf     /*
4940cfc6e8dSAlexander Graf      * We have to generate ser1 first, because Linux takes the first
4950cfc6e8dSAlexander Graf      * device it finds in the dt as serial output device. And we generate
4960cfc6e8dSAlexander Graf      * devices in reverse order to the dt.
4970cfc6e8dSAlexander Graf      */
4989bca0edbSPeter Maydell     if (serial_hd(1)) {
499dffb1dc2SBharat Bhushan         dt_serial_create(fdt, MPC8544_SERIAL1_REGS_OFFSET,
500a053a7ceSAlexander Graf                          soc, mpic, "serial1", 1, false);
50179c0ff2cSAlexander Graf     }
50279c0ff2cSAlexander Graf 
5039bca0edbSPeter Maydell     if (serial_hd(0)) {
504dffb1dc2SBharat Bhushan         dt_serial_create(fdt, MPC8544_SERIAL0_REGS_OFFSET,
505a053a7ceSAlexander Graf                          soc, mpic, "serial0", 0, true);
50679c0ff2cSAlexander Graf     }
5070cfc6e8dSAlexander Graf 
5087abb479cSAndrew Randrianasulu     /* i2c */
5097abb479cSAndrew Randrianasulu     dt_i2c_create(fdt, soc, mpic, "i2c");
5107abb479cSAndrew Randrianasulu 
5117abb479cSAndrew Randrianasulu     dt_rtc_create(fdt, "i2c", "rtc");
5127abb479cSAndrew Randrianasulu 
5137abb479cSAndrew Randrianasulu 
5142fb513d3SGreg Kurz     gutil = g_strdup_printf("%s/global-utilities@%llx", soc,
515dffb1dc2SBharat Bhushan                             MPC8544_UTIL_OFFSET);
5165a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, gutil);
5175a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, gutil, "compatible", "fsl,mpc8544-guts");
5185a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, gutil, "reg", MPC8544_UTIL_OFFSET, 0x1000);
5195a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, gutil, "fsl,has-rstcr", NULL, 0);
5202fb513d3SGreg Kurz     g_free(gutil);
521f5038483SAlexander Graf 
5222fb513d3SGreg Kurz     msi = g_strdup_printf("/%s/msi@%llx", soc, MPC8544_MSI_REGS_OFFSET);
5235a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, msi);
5245a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, msi, "compatible", "fsl,mpic-msi");
5255a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, msi, "reg", MPC8544_MSI_REGS_OFFSET, 0x200);
5265a4348d1SPeter Crosthwaite     msi_ph = qemu_fdt_alloc_phandle(fdt);
5275a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, msi, "msi-available-ranges", 0x0, 0x100);
5285a4348d1SPeter Crosthwaite     qemu_fdt_setprop_phandle(fdt, msi, "interrupt-parent", mpic);
5295a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, msi, "interrupts",
530a911b7a9SAlexander Graf         0xe0, 0x0,
531a911b7a9SAlexander Graf         0xe1, 0x0,
532a911b7a9SAlexander Graf         0xe2, 0x0,
533a911b7a9SAlexander Graf         0xe3, 0x0,
534a911b7a9SAlexander Graf         0xe4, 0x0,
535a911b7a9SAlexander Graf         0xe5, 0x0,
536a911b7a9SAlexander Graf         0xe6, 0x0,
537a911b7a9SAlexander Graf         0xe7, 0x0);
5385a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, msi, "phandle", msi_ph);
5395a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, msi, "linux,phandle", msi_ph);
5402fb513d3SGreg Kurz     g_free(msi);
541a911b7a9SAlexander Graf 
5422fb513d3SGreg Kurz     pci = g_strdup_printf("/pci@%llx",
54303f04809SIgor Mammedov                           pmc->ccsrbar_base + MPC8544_PCI_REGS_OFFSET);
5445a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, pci);
5455a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "cell-index", 0);
5465a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, pci, "compatible", "fsl,mpc8540-pci");
5475a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, pci, "device_type", "pci");
5485a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, pci, "interrupt-map-mask", 0xf800, 0x0,
5490dbc0798SAlexander Graf                            0x0, 0x7);
5505a4348d1SPeter Crosthwaite     pci_map = pci_map_create(fdt, qemu_fdt_get_phandle(fdt, mpic),
55103f04809SIgor Mammedov                              pmc->pci_first_slot, pmc->pci_nr_slots,
552492ec48dSAlexander Graf                              &len);
5535a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, pci, "interrupt-map", pci_map, len);
5545a4348d1SPeter Crosthwaite     qemu_fdt_setprop_phandle(fdt, pci, "interrupt-parent", mpic);
5555a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, pci, "interrupts", 24, 2);
5565a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, pci, "bus-range", 0, 255);
5573627757eSAlexander Graf     for (i = 0; i < 14; i++) {
5580dbc0798SAlexander Graf         pci_ranges[i] = cpu_to_be32(pci_ranges[i]);
5590dbc0798SAlexander Graf     }
5605a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "fsl,msi", msi_ph);
5615a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, pci, "ranges", pci_ranges, sizeof(pci_ranges));
5622eaaac1fSAlexander Graf     qemu_fdt_setprop_cells(fdt, pci, "reg",
56303f04809SIgor Mammedov                            (pmc->ccsrbar_base + MPC8544_PCI_REGS_OFFSET) >> 32,
56403f04809SIgor Mammedov                            (pmc->ccsrbar_base + MPC8544_PCI_REGS_OFFSET),
5652eaaac1fSAlexander Graf                            0, 0x1000);
5665a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "clock-frequency", 66666666);
5675a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "#interrupt-cells", 1);
5685a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "#size-cells", 2);
5695a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "#address-cells", 3);
5705a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, "/aliases", "pci0", pci);
5712fb513d3SGreg Kurz     g_free(pci);
5720dbc0798SAlexander Graf 
57303f04809SIgor Mammedov     if (pmc->has_mpc8xxx_gpio) {
574b88e77f4SAlexander Graf         create_dt_mpc8xxx_gpio(fdt, soc, mpic);
575b88e77f4SAlexander Graf     }
5762fb513d3SGreg Kurz     g_free(soc);
577b88e77f4SAlexander Graf 
578a3fc8396SIgor Mammedov     if (pms->pbus_dev) {
579a3fc8396SIgor Mammedov         platform_bus_create_devtree(pms, fdt, mpic);
580f7087343SAlexander Graf     }
5812fb513d3SGreg Kurz     g_free(mpic);
582f7087343SAlexander Graf 
58303f04809SIgor Mammedov     pmc->fixup_devtree(fdt);
584e6eaabebSScott Wood 
585e6eaabebSScott Wood     if (toplevel_compat) {
5865a4348d1SPeter Crosthwaite         qemu_fdt_setprop(fdt, "/", "compatible", toplevel_compat,
587e6eaabebSScott Wood                          strlen(toplevel_compat) + 1);
588e6eaabebSScott Wood     }
589e6eaabebSScott Wood 
590d1b93565SAlexander Graf done:
59128290f37SAlexander Graf     if (!dry_run) {
5925a4348d1SPeter Crosthwaite         qemu_fdt_dumpdtb(fdt, fdt_size);
59328290f37SAlexander Graf         cpu_physical_memory_write(addr, fdt, fdt_size);
594cba2026aSAlexander Graf     }
595cba2026aSAlexander Graf     ret = fdt_size;
5967ec632b4Spbrook 
5971db09b84Saurel32 out:
598347dd79dSAlexander Graf     g_free(pci_map);
5991db09b84Saurel32 
60004088adbSLiu Yu     return ret;
6011db09b84Saurel32 }
6021db09b84Saurel32 
60328290f37SAlexander Graf typedef struct DeviceTreeParams {
60403f04809SIgor Mammedov     PPCE500MachineState *machine;
60528290f37SAlexander Graf     hwaddr addr;
60628290f37SAlexander Graf     hwaddr initrd_base;
60728290f37SAlexander Graf     hwaddr initrd_size;
608903585deSAlexander Graf     hwaddr kernel_base;
609903585deSAlexander Graf     hwaddr kernel_size;
610f7087343SAlexander Graf     Notifier notifier;
61128290f37SAlexander Graf } DeviceTreeParams;
61228290f37SAlexander Graf 
61328290f37SAlexander Graf static void ppce500_reset_device_tree(void *opaque)
61428290f37SAlexander Graf {
61528290f37SAlexander Graf     DeviceTreeParams *p = opaque;
61603f04809SIgor Mammedov     ppce500_load_device_tree(p->machine, p->addr, p->initrd_base,
617903585deSAlexander Graf                              p->initrd_size, p->kernel_base, p->kernel_size,
618903585deSAlexander Graf                              false);
61928290f37SAlexander Graf }
62028290f37SAlexander Graf 
621f7087343SAlexander Graf static void ppce500_init_notify(Notifier *notifier, void *data)
622f7087343SAlexander Graf {
623f7087343SAlexander Graf     DeviceTreeParams *p = container_of(notifier, DeviceTreeParams, notifier);
624f7087343SAlexander Graf     ppce500_reset_device_tree(p);
625f7087343SAlexander Graf }
626f7087343SAlexander Graf 
62703f04809SIgor Mammedov static int ppce500_prep_device_tree(PPCE500MachineState *machine,
62828290f37SAlexander Graf                                     hwaddr addr,
62928290f37SAlexander Graf                                     hwaddr initrd_base,
630903585deSAlexander Graf                                     hwaddr initrd_size,
631903585deSAlexander Graf                                     hwaddr kernel_base,
632903585deSAlexander Graf                                     hwaddr kernel_size)
63328290f37SAlexander Graf {
63428290f37SAlexander Graf     DeviceTreeParams *p = g_new(DeviceTreeParams, 1);
6353ef96221SMarcel Apfelbaum     p->machine = machine;
63628290f37SAlexander Graf     p->addr = addr;
63728290f37SAlexander Graf     p->initrd_base = initrd_base;
63828290f37SAlexander Graf     p->initrd_size = initrd_size;
639903585deSAlexander Graf     p->kernel_base = kernel_base;
640903585deSAlexander Graf     p->kernel_size = kernel_size;
64128290f37SAlexander Graf 
64228290f37SAlexander Graf     qemu_register_reset(ppce500_reset_device_tree, p);
643f7087343SAlexander Graf     p->notifier.notify = ppce500_init_notify;
644f7087343SAlexander Graf     qemu_add_machine_init_done_notifier(&p->notifier);
64528290f37SAlexander Graf 
64628290f37SAlexander Graf     /* Issue the device tree loader once, so that we get the size of the blob */
64703f04809SIgor Mammedov     return ppce500_load_device_tree(machine, addr, initrd_base, initrd_size,
64803f04809SIgor Mammedov                                     kernel_base, kernel_size, true);
64928290f37SAlexander Graf }
65028290f37SAlexander Graf 
651cba2026aSAlexander Graf /* Create -kernel TLB entries for BookE.  */
652a36848ffSAaron Larson hwaddr booke206_page_size_to_tlb(uint64_t size)
653d1e256feSAlexander Graf {
654ab3dd749SPhilippe Mathieu-Daudé     return 63 - clz64(size / KiB);
655d1e256feSAlexander Graf }
656d1e256feSAlexander Graf 
657cefd3cdbSBharat Bhushan static int booke206_initial_map_tsize(CPUPPCState *env)
6583b989d49SAlexander Graf {
659cba2026aSAlexander Graf     struct boot_info *bi = env->load_info;
660cefd3cdbSBharat Bhushan     hwaddr dt_end;
661cba2026aSAlexander Graf     int ps;
6623b989d49SAlexander Graf 
663cba2026aSAlexander Graf     /* Our initial TLB entry needs to cover everything from 0 to
664cba2026aSAlexander Graf        the device tree top */
665cba2026aSAlexander Graf     dt_end = bi->dt_base + bi->dt_size;
666cba2026aSAlexander Graf     ps = booke206_page_size_to_tlb(dt_end) + 1;
667fb37c302SAlexander Graf     if (ps & 1) {
668fb37c302SAlexander Graf         /* e500v2 can only do even TLB size bits */
669fb37c302SAlexander Graf         ps++;
670fb37c302SAlexander Graf     }
671cefd3cdbSBharat Bhushan     return ps;
672cefd3cdbSBharat Bhushan }
673cefd3cdbSBharat Bhushan 
674cefd3cdbSBharat Bhushan static uint64_t mmubooke_initial_mapsize(CPUPPCState *env)
675cefd3cdbSBharat Bhushan {
676cefd3cdbSBharat Bhushan     int tsize;
677cefd3cdbSBharat Bhushan 
678cefd3cdbSBharat Bhushan     tsize = booke206_initial_map_tsize(env);
679cefd3cdbSBharat Bhushan     return (1ULL << 10 << tsize);
680cefd3cdbSBharat Bhushan }
681cefd3cdbSBharat Bhushan 
682cefd3cdbSBharat Bhushan static void mmubooke_create_initial_mapping(CPUPPCState *env)
683cefd3cdbSBharat Bhushan {
684cefd3cdbSBharat Bhushan     ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0);
685cefd3cdbSBharat Bhushan     hwaddr size;
686cefd3cdbSBharat Bhushan     int ps;
687cefd3cdbSBharat Bhushan 
688cefd3cdbSBharat Bhushan     ps = booke206_initial_map_tsize(env);
689cba2026aSAlexander Graf     size = (ps << MAS1_TSIZE_SHIFT);
690d1e256feSAlexander Graf     tlb->mas1 = MAS1_VALID | size;
691cba2026aSAlexander Graf     tlb->mas2 = 0;
692cba2026aSAlexander Graf     tlb->mas7_3 = 0;
693d1e256feSAlexander Graf     tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
69493dd5e85SScott Wood 
69593dd5e85SScott Wood     env->tlb_dirty = true;
6963b989d49SAlexander Graf }
6973b989d49SAlexander Graf 
698b3305981SScott Wood static void ppce500_cpu_reset_sec(void *opaque)
6995c145dacSAlexander Graf {
70038f92da6SAndreas Färber     PowerPCCPU *cpu = opaque;
701259186a7SAndreas Färber     CPUState *cs = CPU(cpu);
7025c145dacSAlexander Graf 
703259186a7SAndreas Färber     cpu_reset(cs);
7045c145dacSAlexander Graf 
7055c145dacSAlexander Graf     /* Secondary CPU starts in halted state for now. Needs to change when
7065c145dacSAlexander Graf        implementing non-kernel boot. */
707259186a7SAndreas Färber     cs->halted = 1;
70827103424SAndreas Färber     cs->exception_index = EXCP_HLT;
7093b989d49SAlexander Graf }
7103b989d49SAlexander Graf 
711b3305981SScott Wood static void ppce500_cpu_reset(void *opaque)
7123b989d49SAlexander Graf {
71338f92da6SAndreas Färber     PowerPCCPU *cpu = opaque;
714259186a7SAndreas Färber     CPUState *cs = CPU(cpu);
71538f92da6SAndreas Färber     CPUPPCState *env = &cpu->env;
7163b989d49SAlexander Graf     struct boot_info *bi = env->load_info;
7173b989d49SAlexander Graf 
718259186a7SAndreas Färber     cpu_reset(cs);
7193b989d49SAlexander Graf 
7203b989d49SAlexander Graf     /* Set initial guest state. */
721259186a7SAndreas Färber     cs->halted = 0;
722ab3dd749SPhilippe Mathieu-Daudé     env->gpr[1] = (16 * MiB) - 8;
7233b989d49SAlexander Graf     env->gpr[3] = bi->dt_base;
724cefd3cdbSBharat Bhushan     env->gpr[4] = 0;
725cefd3cdbSBharat Bhushan     env->gpr[5] = 0;
726cefd3cdbSBharat Bhushan     env->gpr[6] = EPAPR_MAGIC;
727cefd3cdbSBharat Bhushan     env->gpr[7] = mmubooke_initial_mapsize(env);
728cefd3cdbSBharat Bhushan     env->gpr[8] = 0;
729cefd3cdbSBharat Bhushan     env->gpr[9] = 0;
7303b989d49SAlexander Graf     env->nip = bi->entry;
731cba2026aSAlexander Graf     mmubooke_create_initial_mapping(env);
7323b989d49SAlexander Graf }
7333b989d49SAlexander Graf 
73403f04809SIgor Mammedov static DeviceState *ppce500_init_mpic_qemu(PPCE500MachineState *pms,
7352104d4f5SGreg Kurz                                            IrqLines  *irqs)
73682fc73b6SScott Wood {
73782fc73b6SScott Wood     DeviceState *dev;
73882fc73b6SScott Wood     SysBusDevice *s;
73982fc73b6SScott Wood     int i, j, k;
74003f04809SIgor Mammedov     MachineState *machine = MACHINE(pms);
741fe6b6346SLike Xu     unsigned int smp_cpus = machine->smp.cpus;
74203f04809SIgor Mammedov     const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(pms);
74382fc73b6SScott Wood 
744e1766344SAndreas Färber     dev = qdev_create(NULL, TYPE_OPENPIC);
74503f04809SIgor Mammedov     object_property_add_child(OBJECT(machine), "pic", OBJECT(dev),
746e75ce32aSMichael Davidsaver                               &error_fatal);
74703f04809SIgor Mammedov     qdev_prop_set_uint32(dev, "model", pmc->mpic_version);
748d85937e6SScott Wood     qdev_prop_set_uint32(dev, "nb_cpus", smp_cpus);
749d85937e6SScott Wood 
75082fc73b6SScott Wood     qdev_init_nofail(dev);
75182fc73b6SScott Wood     s = SYS_BUS_DEVICE(dev);
75282fc73b6SScott Wood 
75382fc73b6SScott Wood     k = 0;
75482fc73b6SScott Wood     for (i = 0; i < smp_cpus; i++) {
75582fc73b6SScott Wood         for (j = 0; j < OPENPIC_OUTPUT_NB; j++) {
7562104d4f5SGreg Kurz             sysbus_connect_irq(s, k++, irqs[i].irq[j]);
75782fc73b6SScott Wood         }
75882fc73b6SScott Wood     }
75982fc73b6SScott Wood 
760d85937e6SScott Wood     return dev;
761d85937e6SScott Wood }
762d85937e6SScott Wood 
76303f04809SIgor Mammedov static DeviceState *ppce500_init_mpic_kvm(const PPCE500MachineClass *pmc,
7642104d4f5SGreg Kurz                                           IrqLines *irqs, Error **errp)
765d85937e6SScott Wood {
766fe656ebdSMarkus Armbruster     Error *err = NULL;
767d85937e6SScott Wood     DeviceState *dev;
768d85937e6SScott Wood     CPUState *cs;
769d85937e6SScott Wood 
770dd49c038SAndreas Färber     dev = qdev_create(NULL, TYPE_KVM_OPENPIC);
77103f04809SIgor Mammedov     qdev_prop_set_uint32(dev, "model", pmc->mpic_version);
772d85937e6SScott Wood 
773fe656ebdSMarkus Armbruster     object_property_set_bool(OBJECT(dev), true, "realized", &err);
774fe656ebdSMarkus Armbruster     if (err) {
775fe656ebdSMarkus Armbruster         error_propagate(errp, err);
776fe656ebdSMarkus Armbruster         object_unparent(OBJECT(dev));
777d85937e6SScott Wood         return NULL;
778d85937e6SScott Wood     }
779d85937e6SScott Wood 
780bdc44640SAndreas Färber     CPU_FOREACH(cs) {
781d85937e6SScott Wood         if (kvm_openpic_connect_vcpu(dev, cs)) {
782d85937e6SScott Wood             fprintf(stderr, "%s: failed to connect vcpu to irqchip\n",
783d85937e6SScott Wood                     __func__);
784d85937e6SScott Wood             abort();
785d85937e6SScott Wood         }
786d85937e6SScott Wood     }
787d85937e6SScott Wood 
788d85937e6SScott Wood     return dev;
789d85937e6SScott Wood }
790d85937e6SScott Wood 
79103f04809SIgor Mammedov static DeviceState *ppce500_init_mpic(PPCE500MachineState *pms,
792c91c187fSMichael Davidsaver                                       MemoryRegion *ccsr,
7932104d4f5SGreg Kurz                                       IrqLines *irqs)
794d85937e6SScott Wood {
79503f04809SIgor Mammedov     MachineState *machine = MACHINE(pms);
79603f04809SIgor Mammedov     const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(pms);
797d85937e6SScott Wood     DeviceState *dev = NULL;
798d85937e6SScott Wood     SysBusDevice *s;
799d85937e6SScott Wood 
800d85937e6SScott Wood     if (kvm_enabled()) {
801fe656ebdSMarkus Armbruster         Error *err = NULL;
802d85937e6SScott Wood 
803446f16a6SMarcel Apfelbaum         if (machine_kernel_irqchip_allowed(machine)) {
80403f04809SIgor Mammedov             dev = ppce500_init_mpic_kvm(pmc, irqs, &err);
805d85937e6SScott Wood         }
806446f16a6SMarcel Apfelbaum         if (machine_kernel_irqchip_required(machine) && !dev) {
807c29b77f9SMarkus Armbruster             error_reportf_err(err,
808c29b77f9SMarkus Armbruster                               "kernel_irqchip requested but unavailable: ");
809fe656ebdSMarkus Armbruster             exit(1);
810d85937e6SScott Wood         }
811d85937e6SScott Wood     }
812d85937e6SScott Wood 
813d85937e6SScott Wood     if (!dev) {
81403f04809SIgor Mammedov         dev = ppce500_init_mpic_qemu(pms, irqs);
815d85937e6SScott Wood     }
816d85937e6SScott Wood 
817d85937e6SScott Wood     s = SYS_BUS_DEVICE(dev);
81882fc73b6SScott Wood     memory_region_add_subregion(ccsr, MPC8544_MPIC_REGS_OFFSET,
81982fc73b6SScott Wood                                 s->mmio[0].memory);
82082fc73b6SScott Wood 
821c91c187fSMichael Davidsaver     return dev;
82282fc73b6SScott Wood }
82382fc73b6SScott Wood 
824016f7758SAlexander Graf static void ppce500_power_off(void *opaque, int line, int on)
825016f7758SAlexander Graf {
826016f7758SAlexander Graf     if (on) {
827cf83f140SEric Blake         qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
828016f7758SAlexander Graf     }
829016f7758SAlexander Graf }
830016f7758SAlexander Graf 
83103f04809SIgor Mammedov void ppce500_init(MachineState *machine)
8321db09b84Saurel32 {
83339186d8aSRichard Henderson     MemoryRegion *address_space_mem = get_system_memory();
8342646c133SAvi Kivity     MemoryRegion *ram = g_new(MemoryRegion, 1);
83503f04809SIgor Mammedov     PPCE500MachineState *pms = PPCE500_MACHINE(machine);
83603f04809SIgor Mammedov     const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(machine);
8371db09b84Saurel32     PCIBus *pci_bus;
838e2684c0bSAndreas Färber     CPUPPCState *env = NULL;
8393812c71fSAlexander Graf     uint64_t loadaddr;
8403812c71fSAlexander Graf     hwaddr kernel_base = -1LL;
8413812c71fSAlexander Graf     int kernel_size = 0;
8423812c71fSAlexander Graf     hwaddr dt_base = 0;
8433812c71fSAlexander Graf     hwaddr initrd_base = 0;
8443812c71fSAlexander Graf     int initrd_size = 0;
8453812c71fSAlexander Graf     hwaddr cur_base = 0;
8463812c71fSAlexander Graf     char *filename;
8478d622594SDavid Engraf     const char *payload_name;
8488d622594SDavid Engraf     bool kernel_as_payload;
8493812c71fSAlexander Graf     hwaddr bios_entry = 0;
8508d622594SDavid Engraf     target_long payload_size;
8513812c71fSAlexander Graf     struct boot_info *boot_info;
8523812c71fSAlexander Graf     int dt_size;
85382fc73b6SScott Wood     int i;
854fe6b6346SLike Xu     unsigned int smp_cpus = machine->smp.cpus;
855d575a6ceSBharat Bhushan     /* irq num for pin INTA, INTB, INTC and INTD is 1, 2, 3 and
856d575a6ceSBharat Bhushan      * 4 respectively */
857d575a6ceSBharat Bhushan     unsigned int pci_irq_nrs[PCI_NUM_PINS] = {1, 2, 3, 4};
8582104d4f5SGreg Kurz     IrqLines *irqs;
859c91c187fSMichael Davidsaver     DeviceState *dev, *mpicdev;
860e2684c0bSAndreas Färber     CPUPPCState *firstenv = NULL;
8613eddc1beSBharat Bhushan     MemoryRegion *ccsr_addr_space;
862dffb1dc2SBharat Bhushan     SysBusDevice *s;
8633eddc1beSBharat Bhushan     PPCE500CCSRState *ccsr;
8647abb479cSAndrew Randrianasulu     I2CBus *i2c;
8651db09b84Saurel32 
8662104d4f5SGreg Kurz     irqs = g_new0(IrqLines, smp_cpus);
867e61c36d5SAlexander Graf     for (i = 0; i < smp_cpus; i++) {
868397b457dSAndreas Färber         PowerPCCPU *cpu;
86955e5c285SAndreas Färber         CPUState *cs;
870e61c36d5SAlexander Graf         qemu_irq *input;
871397b457dSAndreas Färber 
87259e816fdSIgor Mammedov         cpu = POWERPC_CPU(cpu_create(machine->cpu_type));
873397b457dSAndreas Färber         env = &cpu->env;
87455e5c285SAndreas Färber         cs = CPU(cpu);
8751db09b84Saurel32 
87600469dc3SValentin Plotkin         if (env->mmu_model != POWERPC_MMU_BOOKE206) {
8776f76b817SAlistair Francis             error_report("MMU model %i not supported by this machine",
87800469dc3SValentin Plotkin                          env->mmu_model);
87900469dc3SValentin Plotkin             exit(1);
88000469dc3SValentin Plotkin         }
88100469dc3SValentin Plotkin 
882e61c36d5SAlexander Graf         if (!firstenv) {
883e61c36d5SAlexander Graf             firstenv = env;
884e61c36d5SAlexander Graf         }
885e61c36d5SAlexander Graf 
886a915249fSAlexander Graf         input = (qemu_irq *)env->irq_inputs;
8872104d4f5SGreg Kurz         irqs[i].irq[OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT];
8882104d4f5SGreg Kurz         irqs[i].irq[OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT];
8896a450df9SAlexander Graf         env->spr_cb[SPR_BOOKE_PIR].default_value = cs->cpu_index = i;
89003f04809SIgor Mammedov         env->mpic_iack = pmc->ccsrbar_base + MPC8544_MPIC_REGS_OFFSET + 0xa0;
891e61c36d5SAlexander Graf 
892a34a92b9SAndreas Färber         ppc_booke_timers_init(cpu, 400000000, PPC_TIMER_E500);
8933b989d49SAlexander Graf 
8943b989d49SAlexander Graf         /* Register reset handler */
8955c145dacSAlexander Graf         if (!i) {
8965c145dacSAlexander Graf             /* Primary CPU */
8975c145dacSAlexander Graf             struct boot_info *boot_info;
898e61c36d5SAlexander Graf             boot_info = g_malloc0(sizeof(struct boot_info));
899b3305981SScott Wood             qemu_register_reset(ppce500_cpu_reset, cpu);
900e61c36d5SAlexander Graf             env->load_info = boot_info;
9015c145dacSAlexander Graf         } else {
9025c145dacSAlexander Graf             /* Secondary CPUs */
903b3305981SScott Wood             qemu_register_reset(ppce500_cpu_reset_sec, cpu);
9045c145dacSAlexander Graf         }
905e61c36d5SAlexander Graf     }
906e61c36d5SAlexander Graf 
907e61c36d5SAlexander Graf     env = firstenv;
9083b989d49SAlexander Graf 
9091db09b84Saurel32     /* Fixup Memory size on a alignment boundary */
9101db09b84Saurel32     ram_size &= ~(RAM_SIZES_ALIGN - 1);
9113ef96221SMarcel Apfelbaum     machine->ram_size = ram_size;
9121db09b84Saurel32 
9131db09b84Saurel32     /* Register Memory */
914e938ba0cSShreyas B. Prabhu     memory_region_allocate_system_memory(ram, NULL, "mpc8544ds.ram", ram_size);
9152646c133SAvi Kivity     memory_region_add_subregion(address_space_mem, 0, ram);
9161db09b84Saurel32 
9173eddc1beSBharat Bhushan     dev = qdev_create(NULL, "e500-ccsr");
9183eddc1beSBharat Bhushan     object_property_add_child(qdev_get_machine(), "e500-ccsr",
9193eddc1beSBharat Bhushan                               OBJECT(dev), NULL);
9203eddc1beSBharat Bhushan     qdev_init_nofail(dev);
9213eddc1beSBharat Bhushan     ccsr = CCSR(dev);
9223eddc1beSBharat Bhushan     ccsr_addr_space = &ccsr->ccsr_space;
92303f04809SIgor Mammedov     memory_region_add_subregion(address_space_mem, pmc->ccsrbar_base,
9243eddc1beSBharat Bhushan                                 ccsr_addr_space);
925dffb1dc2SBharat Bhushan 
92603f04809SIgor Mammedov     mpicdev = ppce500_init_mpic(pms, ccsr_addr_space, irqs);
9271db09b84Saurel32 
9281db09b84Saurel32     /* Serial */
9299bca0edbSPeter Maydell     if (serial_hd(0)) {
9303eddc1beSBharat Bhushan         serial_mm_init(ccsr_addr_space, MPC8544_SERIAL0_REGS_OFFSET,
931c91c187fSMichael Davidsaver                        0, qdev_get_gpio_in(mpicdev, 42), 399193,
9329bca0edbSPeter Maydell                        serial_hd(0), DEVICE_BIG_ENDIAN);
9332d48377aSBlue Swirl     }
9341db09b84Saurel32 
9359bca0edbSPeter Maydell     if (serial_hd(1)) {
9363eddc1beSBharat Bhushan         serial_mm_init(ccsr_addr_space, MPC8544_SERIAL1_REGS_OFFSET,
937c91c187fSMichael Davidsaver                        0, qdev_get_gpio_in(mpicdev, 42), 399193,
9389bca0edbSPeter Maydell                        serial_hd(1), DEVICE_BIG_ENDIAN);
9392d48377aSBlue Swirl     }
9407abb479cSAndrew Randrianasulu         /* I2C */
9417abb479cSAndrew Randrianasulu     dev = qdev_create(NULL, "mpc-i2c");
9427abb479cSAndrew Randrianasulu     s = SYS_BUS_DEVICE(dev);
9437abb479cSAndrew Randrianasulu     qdev_init_nofail(dev);
9447abb479cSAndrew Randrianasulu     sysbus_connect_irq(s, 0, qdev_get_gpio_in(mpicdev, MPC8544_I2C_IRQ));
9457abb479cSAndrew Randrianasulu     memory_region_add_subregion(ccsr_addr_space, MPC8544_I2C_REGS_OFFSET,
9467abb479cSAndrew Randrianasulu                                 sysbus_mmio_get_region(s, 0));
9477abb479cSAndrew Randrianasulu     i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c");
9487abb479cSAndrew Randrianasulu     i2c_create_slave(i2c, "ds1338", RTC_REGS_OFFSET);
9497abb479cSAndrew Randrianasulu 
9501db09b84Saurel32 
951b0fb8423SAlexander Graf     /* General Utility device */
952dffb1dc2SBharat Bhushan     dev = qdev_create(NULL, "mpc8544-guts");
953dffb1dc2SBharat Bhushan     qdev_init_nofail(dev);
954dffb1dc2SBharat Bhushan     s = SYS_BUS_DEVICE(dev);
9553eddc1beSBharat Bhushan     memory_region_add_subregion(ccsr_addr_space, MPC8544_UTIL_OFFSET,
956dffb1dc2SBharat Bhushan                                 sysbus_mmio_get_region(s, 0));
957b0fb8423SAlexander Graf 
9581db09b84Saurel32     /* PCI */
959dffb1dc2SBharat Bhushan     dev = qdev_create(NULL, "e500-pcihost");
960e75ce32aSMichael Davidsaver     object_property_add_child(qdev_get_machine(), "pci-host", OBJECT(dev),
961e75ce32aSMichael Davidsaver                               &error_abort);
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     qdev_init_nofail(dev);
965dffb1dc2SBharat Bhushan     s = SYS_BUS_DEVICE(dev);
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 
990b88e77f4SAlexander Graf         dev = qdev_create(NULL, "mpc8xxx_gpio");
991b88e77f4SAlexander Graf         s = SYS_BUS_DEVICE(dev);
992b88e77f4SAlexander Graf         qdev_init_nofail(dev);
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) {
1004f7087343SAlexander Graf         dev = qdev_create(NULL, 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);
1008f7087343SAlexander Graf         qdev_init_nofail(dev);
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;
10388d622594SDavid Engraf     if (bios_name == 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 {
10468d622594SDavid Engraf         payload_name = bios_name;
10478d622594SDavid Engraf     }
10488d622594SDavid Engraf 
10498d622594SDavid Engraf     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, payload_name);
10508d622594SDavid Engraf 
10514366e1dbSLiam Merwick     payload_size = load_elf(filename, NULL, NULL, NULL,
10524366e1dbSLiam Merwick                             &bios_entry, &loadaddr, NULL,
10538d622594SDavid Engraf                             1, PPC_ELF_MACHINE, 0, 0);
10548d622594SDavid Engraf     if (payload_size < 0) {
10558d622594SDavid Engraf         /*
10568d622594SDavid Engraf          * Hrm. No ELF image? Try a uImage, maybe someone is giving us an
10578d622594SDavid Engraf          * ePAPR compliant kernel
10588d622594SDavid Engraf          */
1059f831f955SNick Hudson         loadaddr = LOAD_UIMAGE_LOADADDR_INVALID;
10608d622594SDavid Engraf         payload_size = load_uimage(filename, &bios_entry, &loadaddr, NULL,
10618d622594SDavid Engraf                                    NULL, NULL);
10628d622594SDavid Engraf         if (payload_size < 0) {
1063371b74e2SMao Zhongyi             error_report("could not load firmware '%s'", filename);
10648d622594SDavid Engraf             exit(1);
10658d622594SDavid Engraf         }
10668d622594SDavid Engraf     }
10678d622594SDavid Engraf 
10688d622594SDavid Engraf     g_free(filename);
10698d622594SDavid Engraf 
10708d622594SDavid Engraf     if (kernel_as_payload) {
10718d622594SDavid Engraf         kernel_base = loadaddr;
10728d622594SDavid Engraf         kernel_size = payload_size;
10738d622594SDavid Engraf     }
10748d622594SDavid Engraf 
10758d622594SDavid Engraf     cur_base = loadaddr + payload_size;
1076ab3dd749SPhilippe Mathieu-Daudé     if (cur_base < 32 * MiB) {
1077b4a5f24aSDavid Engraf         /* u-boot occupies memory up to 32MB, so load blobs above */
1078ab3dd749SPhilippe Mathieu-Daudé         cur_base = 32 * MiB;
1079b4a5f24aSDavid Engraf     }
10808d622594SDavid Engraf 
10818d622594SDavid Engraf     /* Load bare kernel only if no bios/u-boot has been provided */
10828d622594SDavid Engraf     if (machine->kernel_filename && !kernel_as_payload) {
10833812c71fSAlexander Graf         kernel_base = cur_base;
10843812c71fSAlexander Graf         kernel_size = load_image_targphys(machine->kernel_filename,
10853812c71fSAlexander Graf                                           cur_base,
10863812c71fSAlexander Graf                                           ram_size - cur_base);
10871db09b84Saurel32         if (kernel_size < 0) {
10886f76b817SAlistair Francis             error_report("could not load kernel '%s'",
10893ef96221SMarcel Apfelbaum                          machine->kernel_filename);
10901db09b84Saurel32             exit(1);
10911db09b84Saurel32         }
1092528e536eSAlexander Graf 
10933812c71fSAlexander Graf         cur_base += kernel_size;
10941db09b84Saurel32     }
10951db09b84Saurel32 
10961db09b84Saurel32     /* Load initrd. */
10973ef96221SMarcel Apfelbaum     if (machine->initrd_filename) {
1098528e536eSAlexander Graf         initrd_base = (cur_base + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK;
10993ef96221SMarcel Apfelbaum         initrd_size = load_image_targphys(machine->initrd_filename, initrd_base,
1100d7585251Spbrook                                           ram_size - initrd_base);
11011db09b84Saurel32 
11021db09b84Saurel32         if (initrd_size < 0) {
11036f76b817SAlistair Francis             error_report("could not load initial ram disk '%s'",
11043ef96221SMarcel Apfelbaum                          machine->initrd_filename);
11051db09b84Saurel32             exit(1);
11061db09b84Saurel32         }
1107528e536eSAlexander Graf 
1108528e536eSAlexander Graf         cur_base = initrd_base + initrd_size;
11091db09b84Saurel32     }
11101db09b84Saurel32 
11113812c71fSAlexander Graf     /*
11128d622594SDavid Engraf      * Reserve space for dtb behind the kernel image because Linux has a bug
11138d622594SDavid Engraf      * where it can only handle the dtb if it's within the first 64MB of where
11148d622594SDavid Engraf      * <kernel> starts. dtb cannot not reach initrd_base because INITRD_LOAD_PAD
11158d622594SDavid Engraf      * ensures enough space between kernel and initrd.
11163812c71fSAlexander Graf      */
11178d622594SDavid Engraf     dt_base = (loadaddr + payload_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
11188d622594SDavid Engraf     if (dt_base + DTB_MAX_SIZE > ram_size) {
1119371b74e2SMao Zhongyi             error_report("not enough memory for device tree");
11203812c71fSAlexander Graf             exit(1);
11213812c71fSAlexander Graf     }
11225c145dacSAlexander Graf 
112303f04809SIgor Mammedov     dt_size = ppce500_prep_device_tree(pms, dt_base,
1124903585deSAlexander Graf                                        initrd_base, initrd_size,
11253812c71fSAlexander Graf                                        kernel_base, kernel_size);
1126cba2026aSAlexander Graf     if (dt_size < 0) {
11276f76b817SAlistair Francis         error_report("couldn't load device tree");
11281db09b84Saurel32         exit(1);
11291db09b84Saurel32     }
1130b8dec144SAlexander Graf     assert(dt_size < DTB_MAX_SIZE);
11311db09b84Saurel32 
1132e61c36d5SAlexander Graf     boot_info = env->load_info;
11333812c71fSAlexander Graf     boot_info->entry = bios_entry;
11343b989d49SAlexander Graf     boot_info->dt_base = dt_base;
1135cba2026aSAlexander Graf     boot_info->dt_size = dt_size;
11361db09b84Saurel32 }
11373eddc1beSBharat Bhushan 
1138d0c2b0d0Sxiaoqiang zhao static void e500_ccsr_initfn(Object *obj)
11393eddc1beSBharat Bhushan {
1140d0c2b0d0Sxiaoqiang zhao     PPCE500CCSRState *ccsr = CCSR(obj);
1141d0c2b0d0Sxiaoqiang zhao     memory_region_init(&ccsr->ccsr_space, obj, "e500-ccsr",
11423eddc1beSBharat Bhushan                        MPC8544_CCSRBAR_SIZE);
11433eddc1beSBharat Bhushan }
11443eddc1beSBharat Bhushan 
11453eddc1beSBharat Bhushan static const TypeInfo e500_ccsr_info = {
11463eddc1beSBharat Bhushan     .name          = TYPE_CCSR,
11473eddc1beSBharat Bhushan     .parent        = TYPE_SYS_BUS_DEVICE,
11483eddc1beSBharat Bhushan     .instance_size = sizeof(PPCE500CCSRState),
1149d0c2b0d0Sxiaoqiang zhao     .instance_init = e500_ccsr_initfn,
11503eddc1beSBharat Bhushan };
11513eddc1beSBharat Bhushan 
115203f04809SIgor Mammedov static const TypeInfo ppce500_info = {
115303f04809SIgor Mammedov     .name          = TYPE_PPCE500_MACHINE,
115403f04809SIgor Mammedov     .parent        = TYPE_MACHINE,
115503f04809SIgor Mammedov     .abstract      = true,
1156a3fc8396SIgor Mammedov     .instance_size = sizeof(PPCE500MachineState),
115703f04809SIgor Mammedov     .class_size    = sizeof(PPCE500MachineClass),
115803f04809SIgor Mammedov };
115903f04809SIgor Mammedov 
11603eddc1beSBharat Bhushan static void e500_register_types(void)
11613eddc1beSBharat Bhushan {
11623eddc1beSBharat Bhushan     type_register_static(&e500_ccsr_info);
116303f04809SIgor Mammedov     type_register_static(&ppce500_info);
11643eddc1beSBharat Bhushan }
11653eddc1beSBharat Bhushan 
11663eddc1beSBharat Bhushan type_init(e500_register_types)
1167