xref: /qemu/hw/ppc/e500.c (revision 2c65db5e58d2c74921077f6c064ba4c91ebde16a)
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"
19*2c65db5eSPaolo Bonzini #include "qemu/datadir.h"
20ab3dd749SPhilippe Mathieu-Daudé #include "qemu/units.h"
21da34e65cSMarkus Armbruster #include "qapi/error.h"
22e6eaabebSScott Wood #include "e500.h"
233eddc1beSBharat Bhushan #include "e500-ccsr.h"
241422e32dSPaolo Bonzini #include "net/net.h"
251de7afc9SPaolo Bonzini #include "qemu/config-file.h"
260d09e41aSPaolo Bonzini #include "hw/char/serial.h"
27a2cb15b0SMichael S. Tsirkin #include "hw/pci/pci.h"
284a18e7c9SScott Wood #include "hw/boards.h"
299c17d615SPaolo Bonzini #include "sysemu/sysemu.h"
309c17d615SPaolo Bonzini #include "sysemu/kvm.h"
3171e8a915SMarkus Armbruster #include "sysemu/reset.h"
3254d31236SMarkus Armbruster #include "sysemu/runstate.h"
331db09b84Saurel32 #include "kvm_ppc.h"
349c17d615SPaolo Bonzini #include "sysemu/device_tree.h"
350d09e41aSPaolo Bonzini #include "hw/ppc/openpic.h"
368d085cf0SMark Cave-Ayland #include "hw/ppc/openpic_kvm.h"
370d09e41aSPaolo Bonzini #include "hw/ppc/ppc.h"
38a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
394a18e7c9SScott Wood #include "hw/loader.h"
40ca20cf32SBlue Swirl #include "elf.h"
414a18e7c9SScott Wood #include "hw/sysbus.h"
42022c62cbSPaolo Bonzini #include "exec/address-spaces.h"
431de7afc9SPaolo Bonzini #include "qemu/host-utils.h"
44922a01a0SMarkus Armbruster #include "qemu/option.h"
450d09e41aSPaolo Bonzini #include "hw/pci-host/ppce500.h"
46f7087343SAlexander Graf #include "qemu/error-report.h"
47f7087343SAlexander Graf #include "hw/platform-bus.h"
48fdfb7f2cSAlexander Graf #include "hw/net/fsl_etsec/etsec.h"
497abb479cSAndrew Randrianasulu #include "hw/i2c/i2c.h"
5064552b6bSMarkus Armbruster #include "hw/irq.h"
511db09b84Saurel32 
52cefd3cdbSBharat Bhushan #define EPAPR_MAGIC                (0x45504150)
531db09b84Saurel32 #define BINARY_DEVICE_TREE_FILE    "mpc8544ds.dtb"
549dd5eba1SScott Wood #define DTC_LOAD_PAD               0x1800000
5575bb6589SLiu Yu #define DTC_PAD_MASK               0xFFFFF
56ab3dd749SPhilippe Mathieu-Daudé #define DTB_MAX_SIZE               (8 * MiB)
5775bb6589SLiu Yu #define INITRD_LOAD_PAD            0x2000000
5875bb6589SLiu Yu #define INITRD_PAD_MASK            0xFFFFFF
591db09b84Saurel32 
60ab3dd749SPhilippe Mathieu-Daudé #define RAM_SIZES_ALIGN            (64 * MiB)
611db09b84Saurel32 
62b3305981SScott Wood /* TODO: parameterize */
63ed2bc496SAlexander Graf #define MPC8544_CCSRBAR_SIZE       0x00100000ULL
64dffb1dc2SBharat Bhushan #define MPC8544_MPIC_REGS_OFFSET   0x40000ULL
65a911b7a9SAlexander Graf #define MPC8544_MSI_REGS_OFFSET   0x41600ULL
66dffb1dc2SBharat Bhushan #define MPC8544_SERIAL0_REGS_OFFSET 0x4500ULL
67dffb1dc2SBharat Bhushan #define MPC8544_SERIAL1_REGS_OFFSET 0x4600ULL
68dffb1dc2SBharat Bhushan #define MPC8544_PCI_REGS_OFFSET    0x8000ULL
69ed2bc496SAlexander Graf #define MPC8544_PCI_REGS_SIZE      0x1000ULL
70dffb1dc2SBharat Bhushan #define MPC8544_UTIL_OFFSET        0xe0000ULL
71b88e77f4SAlexander Graf #define MPC8XXX_GPIO_OFFSET        0x000FF000ULL
727abb479cSAndrew Randrianasulu #define MPC8544_I2C_REGS_OFFSET    0x3000ULL
7382e345f5SAmit Tomar #define MPC8XXX_GPIO_IRQ           47
747abb479cSAndrew Randrianasulu #define MPC8544_I2C_IRQ            43
757abb479cSAndrew Randrianasulu #define RTC_REGS_OFFSET            0x68
761db09b84Saurel32 
773b989d49SAlexander Graf struct boot_info
783b989d49SAlexander Graf {
793b989d49SAlexander Graf     uint32_t dt_base;
80cba2026aSAlexander Graf     uint32_t dt_size;
813b989d49SAlexander Graf     uint32_t entry;
823b989d49SAlexander Graf };
833b989d49SAlexander Graf 
84347dd79dSAlexander Graf static uint32_t *pci_map_create(void *fdt, uint32_t mpic, int first_slot,
85347dd79dSAlexander Graf                                 int nr_slots, int *len)
860dbc0798SAlexander Graf {
87347dd79dSAlexander Graf     int i = 0;
88347dd79dSAlexander Graf     int slot;
89347dd79dSAlexander Graf     int pci_irq;
909e2c1298SAlexander Graf     int host_irq;
91347dd79dSAlexander Graf     int last_slot = first_slot + nr_slots;
92347dd79dSAlexander Graf     uint32_t *pci_map;
930dbc0798SAlexander Graf 
94347dd79dSAlexander Graf     *len = nr_slots * 4 * 7 * sizeof(uint32_t);
95347dd79dSAlexander Graf     pci_map = g_malloc(*len);
96347dd79dSAlexander Graf 
97347dd79dSAlexander Graf     for (slot = first_slot; slot < last_slot; slot++) {
98347dd79dSAlexander Graf         for (pci_irq = 0; pci_irq < 4; pci_irq++) {
99347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(slot << 11);
100347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(0x0);
101347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(0x0);
102347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(pci_irq + 1);
103347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(mpic);
1049e2c1298SAlexander Graf             host_irq = ppce500_pci_map_irq_slot(slot, pci_irq);
1059e2c1298SAlexander Graf             pci_map[i++] = cpu_to_be32(host_irq + 1);
106347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(0x1);
1070dbc0798SAlexander Graf         }
1080dbc0798SAlexander Graf     }
1090dbc0798SAlexander Graf 
110347dd79dSAlexander Graf     assert((i * sizeof(uint32_t)) == *len);
111347dd79dSAlexander Graf 
112347dd79dSAlexander Graf     return pci_map;
113347dd79dSAlexander Graf }
114347dd79dSAlexander Graf 
115a053a7ceSAlexander Graf static void dt_serial_create(void *fdt, unsigned long long offset,
116a053a7ceSAlexander Graf                              const char *soc, const char *mpic,
117a053a7ceSAlexander Graf                              const char *alias, int idx, bool defcon)
118a053a7ceSAlexander Graf {
1192fb513d3SGreg Kurz     char *ser;
120a053a7ceSAlexander Graf 
1212fb513d3SGreg Kurz     ser = g_strdup_printf("%s/serial@%llx", soc, offset);
1225a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, ser);
1235a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, ser, "device_type", "serial");
1245a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, ser, "compatible", "ns16550");
1255a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, ser, "reg", offset, 0x100);
1265a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, ser, "cell-index", idx);
1275a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, ser, "clock-frequency", 0);
1285a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, ser, "interrupts", 42, 2);
1295a4348d1SPeter Crosthwaite     qemu_fdt_setprop_phandle(fdt, ser, "interrupt-parent", mpic);
1305a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, "/aliases", alias, ser);
131a053a7ceSAlexander Graf 
132a053a7ceSAlexander Graf     if (defcon) {
13390ee4e01SNikunj A Dadhania         /*
13490ee4e01SNikunj A Dadhania          * "linux,stdout-path" and "stdout" properties are deprecated by linux
13590ee4e01SNikunj A Dadhania          * kernel. New platforms should only use the "stdout-path" property. Set
13690ee4e01SNikunj A Dadhania          * the new property and continue using older property to remain
13790ee4e01SNikunj A Dadhania          * compatible with the existing firmware.
13890ee4e01SNikunj A Dadhania          */
1395a4348d1SPeter Crosthwaite         qemu_fdt_setprop_string(fdt, "/chosen", "linux,stdout-path", ser);
14090ee4e01SNikunj A Dadhania         qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", ser);
141a053a7ceSAlexander Graf     }
1422fb513d3SGreg Kurz     g_free(ser);
143a053a7ceSAlexander Graf }
144a053a7ceSAlexander Graf 
145b88e77f4SAlexander Graf static void create_dt_mpc8xxx_gpio(void *fdt, const char *soc, const char *mpic)
146b88e77f4SAlexander Graf {
147b88e77f4SAlexander Graf     hwaddr mmio0 = MPC8XXX_GPIO_OFFSET;
148b88e77f4SAlexander Graf     int irq0 = MPC8XXX_GPIO_IRQ;
149b88e77f4SAlexander Graf     gchar *node = g_strdup_printf("%s/gpio@%"PRIx64, soc, mmio0);
150016f7758SAlexander Graf     gchar *poweroff = g_strdup_printf("%s/power-off", soc);
151016f7758SAlexander Graf     int gpio_ph;
152b88e77f4SAlexander Graf 
153b88e77f4SAlexander Graf     qemu_fdt_add_subnode(fdt, node);
154b88e77f4SAlexander Graf     qemu_fdt_setprop_string(fdt, node, "compatible", "fsl,qoriq-gpio");
155b88e77f4SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "reg", mmio0, 0x1000);
156b88e77f4SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "interrupts", irq0, 0x2);
157b88e77f4SAlexander Graf     qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", mpic);
158b88e77f4SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "#gpio-cells", 2);
159b88e77f4SAlexander Graf     qemu_fdt_setprop(fdt, node, "gpio-controller", NULL, 0);
160016f7758SAlexander Graf     gpio_ph = qemu_fdt_alloc_phandle(fdt);
161016f7758SAlexander Graf     qemu_fdt_setprop_cell(fdt, node, "phandle", gpio_ph);
162016f7758SAlexander Graf     qemu_fdt_setprop_cell(fdt, node, "linux,phandle", gpio_ph);
163016f7758SAlexander Graf 
164016f7758SAlexander Graf     /* Power Off Pin */
165016f7758SAlexander Graf     qemu_fdt_add_subnode(fdt, poweroff);
166016f7758SAlexander Graf     qemu_fdt_setprop_string(fdt, poweroff, "compatible", "gpio-poweroff");
167016f7758SAlexander Graf     qemu_fdt_setprop_cells(fdt, poweroff, "gpios", gpio_ph, 0, 0);
168b88e77f4SAlexander Graf 
169b88e77f4SAlexander Graf     g_free(node);
170016f7758SAlexander Graf     g_free(poweroff);
171b88e77f4SAlexander Graf }
172b88e77f4SAlexander Graf 
1737abb479cSAndrew Randrianasulu static void dt_rtc_create(void *fdt, const char *i2c, const char *alias)
1747abb479cSAndrew Randrianasulu {
1757abb479cSAndrew Randrianasulu     int offset = RTC_REGS_OFFSET;
1767abb479cSAndrew Randrianasulu 
1777abb479cSAndrew Randrianasulu     gchar *rtc = g_strdup_printf("%s/rtc@%"PRIx32, i2c, offset);
1787abb479cSAndrew Randrianasulu     qemu_fdt_add_subnode(fdt, rtc);
1797abb479cSAndrew Randrianasulu     qemu_fdt_setprop_string(fdt, rtc, "compatible", "pericom,pt7c4338");
1807abb479cSAndrew Randrianasulu     qemu_fdt_setprop_cells(fdt, rtc, "reg", offset);
1817abb479cSAndrew Randrianasulu     qemu_fdt_setprop_string(fdt, "/aliases", alias, rtc);
1827abb479cSAndrew Randrianasulu 
1837abb479cSAndrew Randrianasulu     g_free(rtc);
1847abb479cSAndrew Randrianasulu }
1857abb479cSAndrew Randrianasulu 
1867abb479cSAndrew Randrianasulu static void dt_i2c_create(void *fdt, const char *soc, const char *mpic,
1877abb479cSAndrew Randrianasulu                              const char *alias)
1887abb479cSAndrew Randrianasulu {
1897abb479cSAndrew Randrianasulu     hwaddr mmio0 = MPC8544_I2C_REGS_OFFSET;
1907abb479cSAndrew Randrianasulu     int irq0 = MPC8544_I2C_IRQ;
1917abb479cSAndrew Randrianasulu 
1927abb479cSAndrew Randrianasulu     gchar *i2c = g_strdup_printf("%s/i2c@%"PRIx64, soc, mmio0);
1937abb479cSAndrew Randrianasulu     qemu_fdt_add_subnode(fdt, i2c);
1947abb479cSAndrew Randrianasulu     qemu_fdt_setprop_string(fdt, i2c, "device_type", "i2c");
1957abb479cSAndrew Randrianasulu     qemu_fdt_setprop_string(fdt, i2c, "compatible", "fsl-i2c");
1967abb479cSAndrew Randrianasulu     qemu_fdt_setprop_cells(fdt, i2c, "reg", mmio0, 0x14);
1977abb479cSAndrew Randrianasulu     qemu_fdt_setprop_cells(fdt, i2c, "cell-index", 0);
1987abb479cSAndrew Randrianasulu     qemu_fdt_setprop_cells(fdt, i2c, "interrupts", irq0, 0x2);
1997abb479cSAndrew Randrianasulu     qemu_fdt_setprop_phandle(fdt, i2c, "interrupt-parent", mpic);
2007abb479cSAndrew Randrianasulu     qemu_fdt_setprop_string(fdt, "/aliases", alias, i2c);
2017abb479cSAndrew Randrianasulu 
2027abb479cSAndrew Randrianasulu     g_free(i2c);
2037abb479cSAndrew Randrianasulu }
2047abb479cSAndrew Randrianasulu 
2057abb479cSAndrew Randrianasulu 
206f7087343SAlexander Graf typedef struct PlatformDevtreeData {
207f7087343SAlexander Graf     void *fdt;
208f7087343SAlexander Graf     const char *mpic;
209f7087343SAlexander Graf     int irq_start;
210f7087343SAlexander Graf     const char *node;
211f7087343SAlexander Graf     PlatformBusDevice *pbus;
212f7087343SAlexander Graf } PlatformDevtreeData;
213f7087343SAlexander Graf 
214fdfb7f2cSAlexander Graf static int create_devtree_etsec(SysBusDevice *sbdev, PlatformDevtreeData *data)
215fdfb7f2cSAlexander Graf {
216fdfb7f2cSAlexander Graf     eTSEC *etsec = ETSEC_COMMON(sbdev);
217fdfb7f2cSAlexander Graf     PlatformBusDevice *pbus = data->pbus;
218fdfb7f2cSAlexander Graf     hwaddr mmio0 = platform_bus_get_mmio_addr(pbus, sbdev, 0);
219fdfb7f2cSAlexander Graf     int irq0 = platform_bus_get_irqn(pbus, sbdev, 0);
220fdfb7f2cSAlexander Graf     int irq1 = platform_bus_get_irqn(pbus, sbdev, 1);
221fdfb7f2cSAlexander Graf     int irq2 = platform_bus_get_irqn(pbus, sbdev, 2);
222fdfb7f2cSAlexander Graf     gchar *node = g_strdup_printf("/platform/ethernet@%"PRIx64, mmio0);
223fdfb7f2cSAlexander Graf     gchar *group = g_strdup_printf("%s/queue-group", node);
224fdfb7f2cSAlexander Graf     void *fdt = data->fdt;
225fdfb7f2cSAlexander Graf 
226fdfb7f2cSAlexander Graf     assert((int64_t)mmio0 >= 0);
227fdfb7f2cSAlexander Graf     assert(irq0 >= 0);
228fdfb7f2cSAlexander Graf     assert(irq1 >= 0);
229fdfb7f2cSAlexander Graf     assert(irq2 >= 0);
230fdfb7f2cSAlexander Graf 
231fdfb7f2cSAlexander Graf     qemu_fdt_add_subnode(fdt, node);
232fdfb7f2cSAlexander Graf     qemu_fdt_setprop_string(fdt, node, "device_type", "network");
233fdfb7f2cSAlexander Graf     qemu_fdt_setprop_string(fdt, node, "compatible", "fsl,etsec2");
234fdfb7f2cSAlexander Graf     qemu_fdt_setprop_string(fdt, node, "model", "eTSEC");
235fdfb7f2cSAlexander Graf     qemu_fdt_setprop(fdt, node, "local-mac-address", etsec->conf.macaddr.a, 6);
236fdfb7f2cSAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "fixed-link", 0, 1, 1000, 0, 0);
237fdfb7f2cSAlexander Graf 
238fdfb7f2cSAlexander Graf     qemu_fdt_add_subnode(fdt, group);
239fdfb7f2cSAlexander Graf     qemu_fdt_setprop_cells(fdt, group, "reg", mmio0, 0x1000);
240fdfb7f2cSAlexander Graf     qemu_fdt_setprop_cells(fdt, group, "interrupts",
241fdfb7f2cSAlexander Graf         data->irq_start + irq0, 0x2,
242fdfb7f2cSAlexander Graf         data->irq_start + irq1, 0x2,
243fdfb7f2cSAlexander Graf         data->irq_start + irq2, 0x2);
244fdfb7f2cSAlexander Graf 
245fdfb7f2cSAlexander Graf     g_free(node);
246fdfb7f2cSAlexander Graf     g_free(group);
247fdfb7f2cSAlexander Graf 
248fdfb7f2cSAlexander Graf     return 0;
249fdfb7f2cSAlexander Graf }
250fdfb7f2cSAlexander Graf 
2514f01a637SDavid Gibson static void sysbus_device_create_devtree(SysBusDevice *sbdev, void *opaque)
252f7087343SAlexander Graf {
253f7087343SAlexander Graf     PlatformDevtreeData *data = opaque;
254f7087343SAlexander Graf     bool matched = false;
255f7087343SAlexander Graf 
256fdfb7f2cSAlexander Graf     if (object_dynamic_cast(OBJECT(sbdev), TYPE_ETSEC_COMMON)) {
257fdfb7f2cSAlexander Graf         create_devtree_etsec(sbdev, data);
258fdfb7f2cSAlexander Graf         matched = true;
259fdfb7f2cSAlexander Graf     }
260fdfb7f2cSAlexander Graf 
261f7087343SAlexander Graf     if (!matched) {
262f7087343SAlexander Graf         error_report("Device %s is not supported by this machine yet.",
263f7087343SAlexander Graf                      qdev_fw_name(DEVICE(sbdev)));
264f7087343SAlexander Graf         exit(1);
265f7087343SAlexander Graf     }
266f7087343SAlexander Graf }
267f7087343SAlexander Graf 
268a3fc8396SIgor Mammedov static void platform_bus_create_devtree(PPCE500MachineState *pms,
26903f04809SIgor Mammedov                                         void *fdt, const char *mpic)
270f7087343SAlexander Graf {
271a3fc8396SIgor Mammedov     const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(pms);
27203f04809SIgor Mammedov     gchar *node = g_strdup_printf("/platform@%"PRIx64, pmc->platform_bus_base);
273f7087343SAlexander Graf     const char platcomp[] = "qemu,platform\0simple-bus";
27403f04809SIgor Mammedov     uint64_t addr = pmc->platform_bus_base;
27503f04809SIgor Mammedov     uint64_t size = pmc->platform_bus_size;
27603f04809SIgor Mammedov     int irq_start = pmc->platform_bus_first_irq;
277f7087343SAlexander Graf 
278f7087343SAlexander Graf     /* Create a /platform node that we can put all devices into */
279f7087343SAlexander Graf 
280f7087343SAlexander Graf     qemu_fdt_add_subnode(fdt, node);
281f7087343SAlexander Graf     qemu_fdt_setprop(fdt, node, "compatible", platcomp, sizeof(platcomp));
282f7087343SAlexander Graf 
283f7087343SAlexander Graf     /* Our platform bus region is less than 32bit big, so 1 cell is enough for
284f7087343SAlexander Graf        address and size */
285f7087343SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "#size-cells", 1);
286f7087343SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "#address-cells", 1);
287f7087343SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "ranges", 0, addr >> 32, addr, size);
288f7087343SAlexander Graf 
289f7087343SAlexander Graf     qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", mpic);
290f7087343SAlexander Graf 
291a3fc8396SIgor Mammedov     /* Create dt nodes for dynamic devices */
292f7087343SAlexander Graf     PlatformDevtreeData data = {
293f7087343SAlexander Graf         .fdt = fdt,
294f7087343SAlexander Graf         .mpic = mpic,
295f7087343SAlexander Graf         .irq_start = irq_start,
296f7087343SAlexander Graf         .node = node,
297a3fc8396SIgor Mammedov         .pbus = pms->pbus_dev,
298f7087343SAlexander Graf     };
299f7087343SAlexander Graf 
300f7087343SAlexander Graf     /* Loop through all dynamic sysbus devices and create nodes for them */
301f7087343SAlexander Graf     foreach_dynamic_sysbus_device(sysbus_device_create_devtree, &data);
302f7087343SAlexander Graf 
303f7087343SAlexander Graf     g_free(node);
304f7087343SAlexander Graf }
305f7087343SAlexander Graf 
30603f04809SIgor Mammedov static int ppce500_load_device_tree(PPCE500MachineState *pms,
307a8170e5eSAvi Kivity                                     hwaddr addr,
308a8170e5eSAvi Kivity                                     hwaddr initrd_base,
30928290f37SAlexander Graf                                     hwaddr initrd_size,
310903585deSAlexander Graf                                     hwaddr kernel_base,
311903585deSAlexander Graf                                     hwaddr kernel_size,
31228290f37SAlexander Graf                                     bool dry_run)
3131db09b84Saurel32 {
31403f04809SIgor Mammedov     MachineState *machine = MACHINE(pms);
315fe6b6346SLike Xu     unsigned int smp_cpus = machine->smp.cpus;
31603f04809SIgor Mammedov     const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(pms);
31728290f37SAlexander Graf     CPUPPCState *env = first_cpu->env_ptr;
318dbf916d8SAurelien Jarno     int ret = -1;
3193ef96221SMarcel Apfelbaum     uint64_t mem_reg_property[] = { 0, cpu_to_be64(machine->ram_size) };
3207ec632b4Spbrook     int fdt_size;
321dbf916d8SAurelien Jarno     void *fdt;
3225de6b46dSAlexander Graf     uint8_t hypercall[16];
323911d6e7aSAlexander Graf     uint32_t clock_freq = 400000000;
324911d6e7aSAlexander Graf     uint32_t tb_freq = 400000000;
325621d05e3SAlexander Graf     int i;
326ebb9518aSAlexander Graf     char compatible_sb[] = "fsl,mpc8544-immr\0simple-bus";
3272fb513d3SGreg Kurz     char *soc;
3282fb513d3SGreg Kurz     char *mpic;
32919ac9deaSAlexander Graf     uint32_t mpic_ph;
330a911b7a9SAlexander Graf     uint32_t msi_ph;
3312fb513d3SGreg Kurz     char *gutil;
3322fb513d3SGreg Kurz     char *pci;
3332fb513d3SGreg Kurz     char *msi;
334347dd79dSAlexander Graf     uint32_t *pci_map = NULL;
335347dd79dSAlexander Graf     int len;
3363627757eSAlexander Graf     uint32_t pci_ranges[14] =
3373627757eSAlexander Graf         {
33803f04809SIgor Mammedov             0x2000000, 0x0, pmc->pci_mmio_bus_base,
33903f04809SIgor Mammedov             pmc->pci_mmio_base >> 32, pmc->pci_mmio_base,
3403627757eSAlexander Graf             0x0, 0x20000000,
3413627757eSAlexander Graf 
3423627757eSAlexander Graf             0x1000000, 0x0, 0x0,
34303f04809SIgor Mammedov             pmc->pci_pio_base >> 32, pmc->pci_pio_base,
3443627757eSAlexander Graf             0x0, 0x10000,
3453627757eSAlexander Graf         };
3462ff3de68SMarkus Armbruster     QemuOpts *machine_opts = qemu_get_machine_opts();
3472ff3de68SMarkus Armbruster     const char *dtb_file = qemu_opt_get(machine_opts, "dtb");
3482ff3de68SMarkus Armbruster     const char *toplevel_compat = qemu_opt_get(machine_opts, "dt_compatible");
349d1b93565SAlexander Graf 
350d1b93565SAlexander Graf     if (dtb_file) {
351d1b93565SAlexander Graf         char *filename;
352d1b93565SAlexander Graf         filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_file);
353d1b93565SAlexander Graf         if (!filename) {
354d1b93565SAlexander Graf             goto out;
355d1b93565SAlexander Graf         }
356d1b93565SAlexander Graf 
357d1b93565SAlexander Graf         fdt = load_device_tree(filename, &fdt_size);
3582343dd11SMichael Tokarev         g_free(filename);
359d1b93565SAlexander Graf         if (!fdt) {
360d1b93565SAlexander Graf             goto out;
361d1b93565SAlexander Graf         }
362d1b93565SAlexander Graf         goto done;
363d1b93565SAlexander Graf     }
3641db09b84Saurel32 
3652636fcb6SAlexander Graf     fdt = create_device_tree(&fdt_size);
3665cea8590SPaul Brook     if (fdt == NULL) {
3675cea8590SPaul Brook         goto out;
3685cea8590SPaul Brook     }
3691db09b84Saurel32 
3701db09b84Saurel32     /* Manipulate device tree in memory. */
3715a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 2);
3725a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 2);
37351b852b7SAlexander Graf 
3745a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, "/memory");
3755a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, "/memory", "device_type", "memory");
3765a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, "/memory", "reg", mem_reg_property,
3771db09b84Saurel32                      sizeof(mem_reg_property));
3781db09b84Saurel32 
3795a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, "/chosen");
3803b989d49SAlexander Graf     if (initrd_size) {
3815a4348d1SPeter Crosthwaite         ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start",
3821db09b84Saurel32                                     initrd_base);
3833b989d49SAlexander Graf         if (ret < 0) {
3841db09b84Saurel32             fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
3853b989d49SAlexander Graf         }
3861db09b84Saurel32 
3875a4348d1SPeter Crosthwaite         ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
3881db09b84Saurel32                                     (initrd_base + initrd_size));
3893b989d49SAlexander Graf         if (ret < 0) {
3901db09b84Saurel32             fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
3913b989d49SAlexander Graf         }
392903585deSAlexander Graf 
393903585deSAlexander Graf     }
394903585deSAlexander Graf 
395903585deSAlexander Graf     if (kernel_base != -1ULL) {
396903585deSAlexander Graf         qemu_fdt_setprop_cells(fdt, "/chosen", "qemu,boot-kernel",
397903585deSAlexander Graf                                      kernel_base >> 32, kernel_base,
398903585deSAlexander Graf                                      kernel_size >> 32, kernel_size);
3993b989d49SAlexander Graf     }
4001db09b84Saurel32 
4015a4348d1SPeter Crosthwaite     ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
4023ef96221SMarcel Apfelbaum                                       machine->kernel_cmdline);
4031db09b84Saurel32     if (ret < 0)
4041db09b84Saurel32         fprintf(stderr, "couldn't set /chosen/bootargs\n");
4051db09b84Saurel32 
4061db09b84Saurel32     if (kvm_enabled()) {
407911d6e7aSAlexander Graf         /* Read out host's frequencies */
408911d6e7aSAlexander Graf         clock_freq = kvmppc_get_clockfreq();
409911d6e7aSAlexander Graf         tb_freq = kvmppc_get_tbfreq();
4105de6b46dSAlexander Graf 
4115de6b46dSAlexander Graf         /* indicate KVM hypercall interface */
4125a4348d1SPeter Crosthwaite         qemu_fdt_add_subnode(fdt, "/hypervisor");
4135a4348d1SPeter Crosthwaite         qemu_fdt_setprop_string(fdt, "/hypervisor", "compatible",
4145de6b46dSAlexander Graf                                 "linux,kvm");
4155de6b46dSAlexander Graf         kvmppc_get_hypercall(env, hypercall, sizeof(hypercall));
4165a4348d1SPeter Crosthwaite         qemu_fdt_setprop(fdt, "/hypervisor", "hcall-instructions",
4175de6b46dSAlexander Graf                          hypercall, sizeof(hypercall));
4181a61a9aeSStuart Yoder         /* if KVM supports the idle hcall, set property indicating this */
4191a61a9aeSStuart Yoder         if (kvmppc_get_hasidle(env)) {
4205a4348d1SPeter Crosthwaite             qemu_fdt_setprop(fdt, "/hypervisor", "has-idle", NULL, 0);
4211a61a9aeSStuart Yoder         }
4221db09b84Saurel32     }
4231db09b84Saurel32 
424625e665bSAlexander Graf     /* Create CPU nodes */
4255a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, "/cpus");
4265a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 1);
4275a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0);
428625e665bSAlexander Graf 
4291e3debf0SAlexander Graf     /* We need to generate the cpu nodes in reverse order, so Linux can pick
4301e3debf0SAlexander Graf        the first node as boot node and be happy */
4311e3debf0SAlexander Graf     for (i = smp_cpus - 1; i >= 0; i--) {
432440c8152SAndreas Färber         CPUState *cpu;
4332fb513d3SGreg Kurz         char *cpu_name;
43403f04809SIgor Mammedov         uint64_t cpu_release_addr = pmc->spin_base + (i * 0x20);
43510f25a46SAlexander Graf 
436440c8152SAndreas Färber         cpu = qemu_get_cpu(i);
43755e5c285SAndreas Färber         if (cpu == NULL) {
4381e3debf0SAlexander Graf             continue;
4391e3debf0SAlexander Graf         }
440440c8152SAndreas Färber         env = cpu->env_ptr;
4411e3debf0SAlexander Graf 
4422fb513d3SGreg Kurz         cpu_name = g_strdup_printf("/cpus/PowerPC,8544@%x", i);
4435a4348d1SPeter Crosthwaite         qemu_fdt_add_subnode(fdt, cpu_name);
4445a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq);
4455a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq);
4465a4348d1SPeter Crosthwaite         qemu_fdt_setprop_string(fdt, cpu_name, "device_type", "cpu");
4476d536570SSam Bobroff         qemu_fdt_setprop_cell(fdt, cpu_name, "reg", i);
4485a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-line-size",
4491e3debf0SAlexander Graf                               env->dcache_line_size);
4505a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-line-size",
4511e3debf0SAlexander Graf                               env->icache_line_size);
4525a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-size", 0x8000);
4535a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-size", 0x8000);
4545a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "bus-frequency", 0);
45555e5c285SAndreas Färber         if (cpu->cpu_index) {
4565a4348d1SPeter Crosthwaite             qemu_fdt_setprop_string(fdt, cpu_name, "status", "disabled");
4575a4348d1SPeter Crosthwaite             qemu_fdt_setprop_string(fdt, cpu_name, "enable-method",
4585a4348d1SPeter Crosthwaite                                     "spin-table");
4595a4348d1SPeter Crosthwaite             qemu_fdt_setprop_u64(fdt, cpu_name, "cpu-release-addr",
4601d2e5c52SAlexander Graf                                  cpu_release_addr);
4611e3debf0SAlexander Graf         } else {
4625a4348d1SPeter Crosthwaite             qemu_fdt_setprop_string(fdt, cpu_name, "status", "okay");
4631e3debf0SAlexander Graf         }
4642fb513d3SGreg Kurz         g_free(cpu_name);
4651db09b84Saurel32     }
4661db09b84Saurel32 
4675a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, "/aliases");
4685da96624SAlexander Graf     /* XXX These should go into their respective devices' code */
4692fb513d3SGreg Kurz     soc = g_strdup_printf("/soc@%"PRIx64, pmc->ccsrbar_base);
4705a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, soc);
4715a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, soc, "device_type", "soc");
4725a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, soc, "compatible", compatible_sb,
473ebb9518aSAlexander Graf                      sizeof(compatible_sb));
4745a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, soc, "#address-cells", 1);
4755a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, soc, "#size-cells", 1);
4765a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, soc, "ranges", 0x0,
47703f04809SIgor Mammedov                            pmc->ccsrbar_base >> 32, pmc->ccsrbar_base,
4785da96624SAlexander Graf                            MPC8544_CCSRBAR_SIZE);
4795da96624SAlexander Graf     /* XXX should contain a reasonable value */
4805a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, soc, "bus-frequency", 0);
4815da96624SAlexander Graf 
4822fb513d3SGreg Kurz     mpic = g_strdup_printf("%s/pic@%llx", soc, MPC8544_MPIC_REGS_OFFSET);
4835a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, mpic);
4845a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, mpic, "device_type", "open-pic");
4855a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, mpic, "compatible", "fsl,mpic");
4865a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_OFFSET,
487dffb1dc2SBharat Bhushan                            0x40000);
4885a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, mpic, "#address-cells", 0);
4895a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, mpic, "#interrupt-cells", 2);
4905a4348d1SPeter Crosthwaite     mpic_ph = qemu_fdt_alloc_phandle(fdt);
4915a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, mpic, "phandle", mpic_ph);
4925a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, mpic, "linux,phandle", mpic_ph);
4935a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, mpic, "interrupt-controller", NULL, 0);
49419ac9deaSAlexander Graf 
4950cfc6e8dSAlexander Graf     /*
4960cfc6e8dSAlexander Graf      * We have to generate ser1 first, because Linux takes the first
4970cfc6e8dSAlexander Graf      * device it finds in the dt as serial output device. And we generate
4980cfc6e8dSAlexander Graf      * devices in reverse order to the dt.
4990cfc6e8dSAlexander Graf      */
5009bca0edbSPeter Maydell     if (serial_hd(1)) {
501dffb1dc2SBharat Bhushan         dt_serial_create(fdt, MPC8544_SERIAL1_REGS_OFFSET,
502a053a7ceSAlexander Graf                          soc, mpic, "serial1", 1, false);
50379c0ff2cSAlexander Graf     }
50479c0ff2cSAlexander Graf 
5059bca0edbSPeter Maydell     if (serial_hd(0)) {
506dffb1dc2SBharat Bhushan         dt_serial_create(fdt, MPC8544_SERIAL0_REGS_OFFSET,
507a053a7ceSAlexander Graf                          soc, mpic, "serial0", 0, true);
50879c0ff2cSAlexander Graf     }
5090cfc6e8dSAlexander Graf 
5107abb479cSAndrew Randrianasulu     /* i2c */
5117abb479cSAndrew Randrianasulu     dt_i2c_create(fdt, soc, mpic, "i2c");
5127abb479cSAndrew Randrianasulu 
5137abb479cSAndrew Randrianasulu     dt_rtc_create(fdt, "i2c", "rtc");
5147abb479cSAndrew Randrianasulu 
5157abb479cSAndrew Randrianasulu 
5162fb513d3SGreg Kurz     gutil = g_strdup_printf("%s/global-utilities@%llx", soc,
517dffb1dc2SBharat Bhushan                             MPC8544_UTIL_OFFSET);
5185a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, gutil);
5195a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, gutil, "compatible", "fsl,mpc8544-guts");
5205a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, gutil, "reg", MPC8544_UTIL_OFFSET, 0x1000);
5215a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, gutil, "fsl,has-rstcr", NULL, 0);
5222fb513d3SGreg Kurz     g_free(gutil);
523f5038483SAlexander Graf 
5242fb513d3SGreg Kurz     msi = g_strdup_printf("/%s/msi@%llx", soc, MPC8544_MSI_REGS_OFFSET);
5255a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, msi);
5265a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, msi, "compatible", "fsl,mpic-msi");
5275a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, msi, "reg", MPC8544_MSI_REGS_OFFSET, 0x200);
5285a4348d1SPeter Crosthwaite     msi_ph = qemu_fdt_alloc_phandle(fdt);
5295a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, msi, "msi-available-ranges", 0x0, 0x100);
5305a4348d1SPeter Crosthwaite     qemu_fdt_setprop_phandle(fdt, msi, "interrupt-parent", mpic);
5315a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, msi, "interrupts",
532a911b7a9SAlexander Graf         0xe0, 0x0,
533a911b7a9SAlexander Graf         0xe1, 0x0,
534a911b7a9SAlexander Graf         0xe2, 0x0,
535a911b7a9SAlexander Graf         0xe3, 0x0,
536a911b7a9SAlexander Graf         0xe4, 0x0,
537a911b7a9SAlexander Graf         0xe5, 0x0,
538a911b7a9SAlexander Graf         0xe6, 0x0,
539a911b7a9SAlexander Graf         0xe7, 0x0);
5405a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, msi, "phandle", msi_ph);
5415a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, msi, "linux,phandle", msi_ph);
5422fb513d3SGreg Kurz     g_free(msi);
543a911b7a9SAlexander Graf 
5442fb513d3SGreg Kurz     pci = g_strdup_printf("/pci@%llx",
54503f04809SIgor Mammedov                           pmc->ccsrbar_base + MPC8544_PCI_REGS_OFFSET);
5465a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, pci);
5475a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "cell-index", 0);
5485a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, pci, "compatible", "fsl,mpc8540-pci");
5495a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, pci, "device_type", "pci");
5505a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, pci, "interrupt-map-mask", 0xf800, 0x0,
5510dbc0798SAlexander Graf                            0x0, 0x7);
5525a4348d1SPeter Crosthwaite     pci_map = pci_map_create(fdt, qemu_fdt_get_phandle(fdt, mpic),
55303f04809SIgor Mammedov                              pmc->pci_first_slot, pmc->pci_nr_slots,
554492ec48dSAlexander Graf                              &len);
5555a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, pci, "interrupt-map", pci_map, len);
5565a4348d1SPeter Crosthwaite     qemu_fdt_setprop_phandle(fdt, pci, "interrupt-parent", mpic);
5575a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, pci, "interrupts", 24, 2);
5585a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, pci, "bus-range", 0, 255);
5593627757eSAlexander Graf     for (i = 0; i < 14; i++) {
5600dbc0798SAlexander Graf         pci_ranges[i] = cpu_to_be32(pci_ranges[i]);
5610dbc0798SAlexander Graf     }
5625a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "fsl,msi", msi_ph);
5635a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, pci, "ranges", pci_ranges, sizeof(pci_ranges));
5642eaaac1fSAlexander Graf     qemu_fdt_setprop_cells(fdt, pci, "reg",
56503f04809SIgor Mammedov                            (pmc->ccsrbar_base + MPC8544_PCI_REGS_OFFSET) >> 32,
56603f04809SIgor Mammedov                            (pmc->ccsrbar_base + MPC8544_PCI_REGS_OFFSET),
5672eaaac1fSAlexander Graf                            0, 0x1000);
5685a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "clock-frequency", 66666666);
5695a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "#interrupt-cells", 1);
5705a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "#size-cells", 2);
5715a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "#address-cells", 3);
5725a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, "/aliases", "pci0", pci);
5732fb513d3SGreg Kurz     g_free(pci);
5740dbc0798SAlexander Graf 
57503f04809SIgor Mammedov     if (pmc->has_mpc8xxx_gpio) {
576b88e77f4SAlexander Graf         create_dt_mpc8xxx_gpio(fdt, soc, mpic);
577b88e77f4SAlexander Graf     }
5782fb513d3SGreg Kurz     g_free(soc);
579b88e77f4SAlexander Graf 
580a3fc8396SIgor Mammedov     if (pms->pbus_dev) {
581a3fc8396SIgor Mammedov         platform_bus_create_devtree(pms, fdt, mpic);
582f7087343SAlexander Graf     }
5832fb513d3SGreg Kurz     g_free(mpic);
584f7087343SAlexander Graf 
58503f04809SIgor Mammedov     pmc->fixup_devtree(fdt);
586e6eaabebSScott Wood 
587e6eaabebSScott Wood     if (toplevel_compat) {
5885a4348d1SPeter Crosthwaite         qemu_fdt_setprop(fdt, "/", "compatible", toplevel_compat,
589e6eaabebSScott Wood                          strlen(toplevel_compat) + 1);
590e6eaabebSScott Wood     }
591e6eaabebSScott Wood 
592d1b93565SAlexander Graf done:
59328290f37SAlexander Graf     if (!dry_run) {
5945a4348d1SPeter Crosthwaite         qemu_fdt_dumpdtb(fdt, fdt_size);
59528290f37SAlexander Graf         cpu_physical_memory_write(addr, fdt, fdt_size);
596cba2026aSAlexander Graf     }
597cba2026aSAlexander Graf     ret = fdt_size;
598b2fb7a43SPan Nengyuan     g_free(fdt);
5997ec632b4Spbrook 
6001db09b84Saurel32 out:
601347dd79dSAlexander Graf     g_free(pci_map);
6021db09b84Saurel32 
60304088adbSLiu Yu     return ret;
6041db09b84Saurel32 }
6051db09b84Saurel32 
60628290f37SAlexander Graf typedef struct DeviceTreeParams {
60703f04809SIgor Mammedov     PPCE500MachineState *machine;
60828290f37SAlexander Graf     hwaddr addr;
60928290f37SAlexander Graf     hwaddr initrd_base;
61028290f37SAlexander Graf     hwaddr initrd_size;
611903585deSAlexander Graf     hwaddr kernel_base;
612903585deSAlexander Graf     hwaddr kernel_size;
613f7087343SAlexander Graf     Notifier notifier;
61428290f37SAlexander Graf } DeviceTreeParams;
61528290f37SAlexander Graf 
61628290f37SAlexander Graf static void ppce500_reset_device_tree(void *opaque)
61728290f37SAlexander Graf {
61828290f37SAlexander Graf     DeviceTreeParams *p = opaque;
61903f04809SIgor Mammedov     ppce500_load_device_tree(p->machine, p->addr, p->initrd_base,
620903585deSAlexander Graf                              p->initrd_size, p->kernel_base, p->kernel_size,
621903585deSAlexander Graf                              false);
62228290f37SAlexander Graf }
62328290f37SAlexander Graf 
624f7087343SAlexander Graf static void ppce500_init_notify(Notifier *notifier, void *data)
625f7087343SAlexander Graf {
626f7087343SAlexander Graf     DeviceTreeParams *p = container_of(notifier, DeviceTreeParams, notifier);
627f7087343SAlexander Graf     ppce500_reset_device_tree(p);
628f7087343SAlexander Graf }
629f7087343SAlexander Graf 
63003f04809SIgor Mammedov static int ppce500_prep_device_tree(PPCE500MachineState *machine,
63128290f37SAlexander Graf                                     hwaddr addr,
63228290f37SAlexander Graf                                     hwaddr initrd_base,
633903585deSAlexander Graf                                     hwaddr initrd_size,
634903585deSAlexander Graf                                     hwaddr kernel_base,
635903585deSAlexander Graf                                     hwaddr kernel_size)
63628290f37SAlexander Graf {
63728290f37SAlexander Graf     DeviceTreeParams *p = g_new(DeviceTreeParams, 1);
6383ef96221SMarcel Apfelbaum     p->machine = machine;
63928290f37SAlexander Graf     p->addr = addr;
64028290f37SAlexander Graf     p->initrd_base = initrd_base;
64128290f37SAlexander Graf     p->initrd_size = initrd_size;
642903585deSAlexander Graf     p->kernel_base = kernel_base;
643903585deSAlexander Graf     p->kernel_size = kernel_size;
64428290f37SAlexander Graf 
64528290f37SAlexander Graf     qemu_register_reset(ppce500_reset_device_tree, p);
646f7087343SAlexander Graf     p->notifier.notify = ppce500_init_notify;
647f7087343SAlexander Graf     qemu_add_machine_init_done_notifier(&p->notifier);
64828290f37SAlexander Graf 
64928290f37SAlexander Graf     /* Issue the device tree loader once, so that we get the size of the blob */
65003f04809SIgor Mammedov     return ppce500_load_device_tree(machine, addr, initrd_base, initrd_size,
65103f04809SIgor Mammedov                                     kernel_base, kernel_size, true);
65228290f37SAlexander Graf }
65328290f37SAlexander Graf 
654cba2026aSAlexander Graf /* Create -kernel TLB entries for BookE.  */
655a36848ffSAaron Larson hwaddr booke206_page_size_to_tlb(uint64_t size)
656d1e256feSAlexander Graf {
657ab3dd749SPhilippe Mathieu-Daudé     return 63 - clz64(size / KiB);
658d1e256feSAlexander Graf }
659d1e256feSAlexander Graf 
660cefd3cdbSBharat Bhushan static int booke206_initial_map_tsize(CPUPPCState *env)
6613b989d49SAlexander Graf {
662cba2026aSAlexander Graf     struct boot_info *bi = env->load_info;
663cefd3cdbSBharat Bhushan     hwaddr dt_end;
664cba2026aSAlexander Graf     int ps;
6653b989d49SAlexander Graf 
666cba2026aSAlexander Graf     /* Our initial TLB entry needs to cover everything from 0 to
667cba2026aSAlexander Graf        the device tree top */
668cba2026aSAlexander Graf     dt_end = bi->dt_base + bi->dt_size;
669cba2026aSAlexander Graf     ps = booke206_page_size_to_tlb(dt_end) + 1;
670fb37c302SAlexander Graf     if (ps & 1) {
671fb37c302SAlexander Graf         /* e500v2 can only do even TLB size bits */
672fb37c302SAlexander Graf         ps++;
673fb37c302SAlexander Graf     }
674cefd3cdbSBharat Bhushan     return ps;
675cefd3cdbSBharat Bhushan }
676cefd3cdbSBharat Bhushan 
677cefd3cdbSBharat Bhushan static uint64_t mmubooke_initial_mapsize(CPUPPCState *env)
678cefd3cdbSBharat Bhushan {
679cefd3cdbSBharat Bhushan     int tsize;
680cefd3cdbSBharat Bhushan 
681cefd3cdbSBharat Bhushan     tsize = booke206_initial_map_tsize(env);
682cefd3cdbSBharat Bhushan     return (1ULL << 10 << tsize);
683cefd3cdbSBharat Bhushan }
684cefd3cdbSBharat Bhushan 
685cefd3cdbSBharat Bhushan static void mmubooke_create_initial_mapping(CPUPPCState *env)
686cefd3cdbSBharat Bhushan {
687cefd3cdbSBharat Bhushan     ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0);
688cefd3cdbSBharat Bhushan     hwaddr size;
689cefd3cdbSBharat Bhushan     int ps;
690cefd3cdbSBharat Bhushan 
691cefd3cdbSBharat Bhushan     ps = booke206_initial_map_tsize(env);
692cba2026aSAlexander Graf     size = (ps << MAS1_TSIZE_SHIFT);
693d1e256feSAlexander Graf     tlb->mas1 = MAS1_VALID | size;
694cba2026aSAlexander Graf     tlb->mas2 = 0;
695cba2026aSAlexander Graf     tlb->mas7_3 = 0;
696d1e256feSAlexander Graf     tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
69793dd5e85SScott Wood 
69893dd5e85SScott Wood     env->tlb_dirty = true;
6993b989d49SAlexander Graf }
7003b989d49SAlexander Graf 
701b3305981SScott Wood static void ppce500_cpu_reset_sec(void *opaque)
7025c145dacSAlexander Graf {
70338f92da6SAndreas Färber     PowerPCCPU *cpu = opaque;
704259186a7SAndreas Färber     CPUState *cs = CPU(cpu);
7055c145dacSAlexander Graf 
706259186a7SAndreas Färber     cpu_reset(cs);
7075c145dacSAlexander Graf 
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 
7443e80f690SMarkus Armbruster     dev = qdev_new(TYPE_OPENPIC);
745d2623129SMarkus Armbruster     object_property_add_child(OBJECT(machine), "pic", OBJECT(dev));
74603f04809SIgor Mammedov     qdev_prop_set_uint32(dev, "model", pmc->mpic_version);
747d85937e6SScott Wood     qdev_prop_set_uint32(dev, "nb_cpus", smp_cpus);
748d85937e6SScott Wood 
74982fc73b6SScott Wood     s = SYS_BUS_DEVICE(dev);
7503c6ef471SMarkus Armbruster     sysbus_realize_and_unref(s, &error_fatal);
75182fc73b6SScott Wood 
75282fc73b6SScott Wood     k = 0;
75382fc73b6SScott Wood     for (i = 0; i < smp_cpus; i++) {
75482fc73b6SScott Wood         for (j = 0; j < OPENPIC_OUTPUT_NB; j++) {
7552104d4f5SGreg Kurz             sysbus_connect_irq(s, k++, irqs[i].irq[j]);
75682fc73b6SScott Wood         }
75782fc73b6SScott Wood     }
75882fc73b6SScott Wood 
759d85937e6SScott Wood     return dev;
760d85937e6SScott Wood }
761d85937e6SScott Wood 
76203f04809SIgor Mammedov static DeviceState *ppce500_init_mpic_kvm(const PPCE500MachineClass *pmc,
7632104d4f5SGreg Kurz                                           IrqLines *irqs, Error **errp)
764d85937e6SScott Wood {
765d85937e6SScott Wood     DeviceState *dev;
766d85937e6SScott Wood     CPUState *cs;
767d85937e6SScott Wood 
7683e80f690SMarkus Armbruster     dev = qdev_new(TYPE_KVM_OPENPIC);
76903f04809SIgor Mammedov     qdev_prop_set_uint32(dev, "model", pmc->mpic_version);
770d85937e6SScott Wood 
771668f62ecSMarkus Armbruster     if (!sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), errp)) {
772fe656ebdSMarkus Armbruster         object_unparent(OBJECT(dev));
773d85937e6SScott Wood         return NULL;
774d85937e6SScott Wood     }
775d85937e6SScott Wood 
776bdc44640SAndreas Färber     CPU_FOREACH(cs) {
777d85937e6SScott Wood         if (kvm_openpic_connect_vcpu(dev, cs)) {
778d85937e6SScott Wood             fprintf(stderr, "%s: failed to connect vcpu to irqchip\n",
779d85937e6SScott Wood                     __func__);
780d85937e6SScott Wood             abort();
781d85937e6SScott Wood         }
782d85937e6SScott Wood     }
783d85937e6SScott Wood 
784d85937e6SScott Wood     return dev;
785d85937e6SScott Wood }
786d85937e6SScott Wood 
78703f04809SIgor Mammedov static DeviceState *ppce500_init_mpic(PPCE500MachineState *pms,
788c91c187fSMichael Davidsaver                                       MemoryRegion *ccsr,
7892104d4f5SGreg Kurz                                       IrqLines *irqs)
790d85937e6SScott Wood {
79103f04809SIgor Mammedov     const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(pms);
792d85937e6SScott Wood     DeviceState *dev = NULL;
793d85937e6SScott Wood     SysBusDevice *s;
794d85937e6SScott Wood 
795d85937e6SScott Wood     if (kvm_enabled()) {
796fe656ebdSMarkus Armbruster         Error *err = NULL;
797d85937e6SScott Wood 
7984376c40dSPaolo Bonzini         if (kvm_kernel_irqchip_allowed()) {
79903f04809SIgor Mammedov             dev = ppce500_init_mpic_kvm(pmc, irqs, &err);
800d85937e6SScott Wood         }
8014376c40dSPaolo Bonzini         if (kvm_kernel_irqchip_required() && !dev) {
802c29b77f9SMarkus Armbruster             error_reportf_err(err,
803c29b77f9SMarkus Armbruster                               "kernel_irqchip requested but unavailable: ");
804fe656ebdSMarkus Armbruster             exit(1);
805d85937e6SScott Wood         }
806d85937e6SScott Wood     }
807d85937e6SScott Wood 
808d85937e6SScott Wood     if (!dev) {
80903f04809SIgor Mammedov         dev = ppce500_init_mpic_qemu(pms, irqs);
810d85937e6SScott Wood     }
811d85937e6SScott Wood 
812d85937e6SScott Wood     s = SYS_BUS_DEVICE(dev);
81382fc73b6SScott Wood     memory_region_add_subregion(ccsr, MPC8544_MPIC_REGS_OFFSET,
81482fc73b6SScott Wood                                 s->mmio[0].memory);
81582fc73b6SScott Wood 
816c91c187fSMichael Davidsaver     return dev;
81782fc73b6SScott Wood }
81882fc73b6SScott Wood 
819016f7758SAlexander Graf static void ppce500_power_off(void *opaque, int line, int on)
820016f7758SAlexander Graf {
821016f7758SAlexander Graf     if (on) {
822cf83f140SEric Blake         qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
823016f7758SAlexander Graf     }
824016f7758SAlexander Graf }
825016f7758SAlexander Graf 
82603f04809SIgor Mammedov void ppce500_init(MachineState *machine)
8271db09b84Saurel32 {
82839186d8aSRichard Henderson     MemoryRegion *address_space_mem = get_system_memory();
82903f04809SIgor Mammedov     PPCE500MachineState *pms = PPCE500_MACHINE(machine);
83003f04809SIgor Mammedov     const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(machine);
8311db09b84Saurel32     PCIBus *pci_bus;
832e2684c0bSAndreas Färber     CPUPPCState *env = NULL;
8333812c71fSAlexander Graf     uint64_t loadaddr;
8343812c71fSAlexander Graf     hwaddr kernel_base = -1LL;
8353812c71fSAlexander Graf     int kernel_size = 0;
8363812c71fSAlexander Graf     hwaddr dt_base = 0;
8373812c71fSAlexander Graf     hwaddr initrd_base = 0;
8383812c71fSAlexander Graf     int initrd_size = 0;
8393812c71fSAlexander Graf     hwaddr cur_base = 0;
8403812c71fSAlexander Graf     char *filename;
8418d622594SDavid Engraf     const char *payload_name;
8428d622594SDavid Engraf     bool kernel_as_payload;
8433812c71fSAlexander Graf     hwaddr bios_entry = 0;
8448d622594SDavid Engraf     target_long payload_size;
8453812c71fSAlexander Graf     struct boot_info *boot_info;
8463812c71fSAlexander Graf     int dt_size;
84782fc73b6SScott Wood     int i;
848fe6b6346SLike Xu     unsigned int smp_cpus = machine->smp.cpus;
849d575a6ceSBharat Bhushan     /* irq num for pin INTA, INTB, INTC and INTD is 1, 2, 3 and
850d575a6ceSBharat Bhushan      * 4 respectively */
851d575a6ceSBharat Bhushan     unsigned int pci_irq_nrs[PCI_NUM_PINS] = {1, 2, 3, 4};
8522104d4f5SGreg Kurz     IrqLines *irqs;
853c91c187fSMichael Davidsaver     DeviceState *dev, *mpicdev;
854e2684c0bSAndreas Färber     CPUPPCState *firstenv = NULL;
8553eddc1beSBharat Bhushan     MemoryRegion *ccsr_addr_space;
856dffb1dc2SBharat Bhushan     SysBusDevice *s;
8573eddc1beSBharat Bhushan     PPCE500CCSRState *ccsr;
8587abb479cSAndrew Randrianasulu     I2CBus *i2c;
8591db09b84Saurel32 
8602104d4f5SGreg Kurz     irqs = g_new0(IrqLines, smp_cpus);
861e61c36d5SAlexander Graf     for (i = 0; i < smp_cpus; i++) {
862397b457dSAndreas Färber         PowerPCCPU *cpu;
86355e5c285SAndreas Färber         CPUState *cs;
864e61c36d5SAlexander Graf         qemu_irq *input;
865397b457dSAndreas Färber 
866a2c93f06SThiago Jung Bauermann         cpu = POWERPC_CPU(object_new(machine->cpu_type));
867397b457dSAndreas Färber         env = &cpu->env;
86855e5c285SAndreas Färber         cs = CPU(cpu);
8691db09b84Saurel32 
87000469dc3SValentin Plotkin         if (env->mmu_model != POWERPC_MMU_BOOKE206) {
8716f76b817SAlistair Francis             error_report("MMU model %i not supported by this machine",
87200469dc3SValentin Plotkin                          env->mmu_model);
87300469dc3SValentin Plotkin             exit(1);
87400469dc3SValentin Plotkin         }
87500469dc3SValentin Plotkin 
876a2c93f06SThiago Jung Bauermann         /*
877a2c93f06SThiago Jung Bauermann          * Secondary CPU starts in halted state for now. Needs to change
878a2c93f06SThiago Jung Bauermann          * when implementing non-kernel boot.
879a2c93f06SThiago Jung Bauermann          */
880a2c93f06SThiago Jung Bauermann         object_property_set_bool(OBJECT(cs), "start-powered-off", i != 0,
881a2c93f06SThiago Jung Bauermann                                  &error_fatal);
882a2c93f06SThiago Jung Bauermann         qdev_realize_and_unref(DEVICE(cs), NULL, &error_fatal);
883a2c93f06SThiago Jung Bauermann 
884e61c36d5SAlexander Graf         if (!firstenv) {
885e61c36d5SAlexander Graf             firstenv = env;
886e61c36d5SAlexander Graf         }
887e61c36d5SAlexander Graf 
888a915249fSAlexander Graf         input = (qemu_irq *)env->irq_inputs;
8892104d4f5SGreg Kurz         irqs[i].irq[OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT];
8902104d4f5SGreg Kurz         irqs[i].irq[OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT];
8916a450df9SAlexander Graf         env->spr_cb[SPR_BOOKE_PIR].default_value = cs->cpu_index = i;
89203f04809SIgor Mammedov         env->mpic_iack = pmc->ccsrbar_base + MPC8544_MPIC_REGS_OFFSET + 0xa0;
893e61c36d5SAlexander Graf 
894a34a92b9SAndreas Färber         ppc_booke_timers_init(cpu, 400000000, PPC_TIMER_E500);
8953b989d49SAlexander Graf 
8963b989d49SAlexander Graf         /* Register reset handler */
8975c145dacSAlexander Graf         if (!i) {
8985c145dacSAlexander Graf             /* Primary CPU */
8995c145dacSAlexander Graf             struct boot_info *boot_info;
900e61c36d5SAlexander Graf             boot_info = g_malloc0(sizeof(struct boot_info));
901b3305981SScott Wood             qemu_register_reset(ppce500_cpu_reset, cpu);
902e61c36d5SAlexander Graf             env->load_info = boot_info;
9035c145dacSAlexander Graf         } else {
9045c145dacSAlexander Graf             /* Secondary CPUs */
905b3305981SScott Wood             qemu_register_reset(ppce500_cpu_reset_sec, cpu);
9065c145dacSAlexander Graf         }
907e61c36d5SAlexander Graf     }
908e61c36d5SAlexander Graf 
909e61c36d5SAlexander Graf     env = firstenv;
9103b989d49SAlexander Graf 
9113538e846SIgor Mammedov     if (!QEMU_IS_ALIGNED(machine->ram_size, RAM_SIZES_ALIGN)) {
9123538e846SIgor Mammedov         error_report("RAM size must be multiple of %" PRIu64, RAM_SIZES_ALIGN);
9133538e846SIgor Mammedov         exit(EXIT_FAILURE);
9143538e846SIgor Mammedov     }
9151db09b84Saurel32 
9161db09b84Saurel32     /* Register Memory */
91797316645SIgor Mammedov     memory_region_add_subregion(address_space_mem, 0, machine->ram);
9181db09b84Saurel32 
9193e80f690SMarkus Armbruster     dev = qdev_new("e500-ccsr");
9203eddc1beSBharat Bhushan     object_property_add_child(qdev_get_machine(), "e500-ccsr",
921d2623129SMarkus Armbruster                               OBJECT(dev));
9223c6ef471SMarkus Armbruster     sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
9233eddc1beSBharat Bhushan     ccsr = CCSR(dev);
9243eddc1beSBharat Bhushan     ccsr_addr_space = &ccsr->ccsr_space;
92503f04809SIgor Mammedov     memory_region_add_subregion(address_space_mem, pmc->ccsrbar_base,
9263eddc1beSBharat Bhushan                                 ccsr_addr_space);
927dffb1dc2SBharat Bhushan 
92803f04809SIgor Mammedov     mpicdev = ppce500_init_mpic(pms, ccsr_addr_space, irqs);
9291db09b84Saurel32 
9301db09b84Saurel32     /* Serial */
9319bca0edbSPeter Maydell     if (serial_hd(0)) {
9323eddc1beSBharat Bhushan         serial_mm_init(ccsr_addr_space, MPC8544_SERIAL0_REGS_OFFSET,
933c91c187fSMichael Davidsaver                        0, qdev_get_gpio_in(mpicdev, 42), 399193,
9349bca0edbSPeter Maydell                        serial_hd(0), DEVICE_BIG_ENDIAN);
9352d48377aSBlue Swirl     }
9361db09b84Saurel32 
9379bca0edbSPeter Maydell     if (serial_hd(1)) {
9383eddc1beSBharat Bhushan         serial_mm_init(ccsr_addr_space, MPC8544_SERIAL1_REGS_OFFSET,
939c91c187fSMichael Davidsaver                        0, qdev_get_gpio_in(mpicdev, 42), 399193,
9409bca0edbSPeter Maydell                        serial_hd(1), DEVICE_BIG_ENDIAN);
9412d48377aSBlue Swirl     }
9427abb479cSAndrew Randrianasulu         /* I2C */
9433e80f690SMarkus Armbruster     dev = qdev_new("mpc-i2c");
9447abb479cSAndrew Randrianasulu     s = SYS_BUS_DEVICE(dev);
9453c6ef471SMarkus Armbruster     sysbus_realize_and_unref(s, &error_fatal);
9467abb479cSAndrew Randrianasulu     sysbus_connect_irq(s, 0, qdev_get_gpio_in(mpicdev, MPC8544_I2C_IRQ));
9477abb479cSAndrew Randrianasulu     memory_region_add_subregion(ccsr_addr_space, MPC8544_I2C_REGS_OFFSET,
9487abb479cSAndrew Randrianasulu                                 sysbus_mmio_get_region(s, 0));
9497abb479cSAndrew Randrianasulu     i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c");
9501373b15bSPhilippe Mathieu-Daudé     i2c_slave_create_simple(i2c, "ds1338", RTC_REGS_OFFSET);
9517abb479cSAndrew Randrianasulu 
9521db09b84Saurel32 
953b0fb8423SAlexander Graf     /* General Utility device */
9543e80f690SMarkus Armbruster     dev = qdev_new("mpc8544-guts");
955dffb1dc2SBharat Bhushan     s = SYS_BUS_DEVICE(dev);
9563c6ef471SMarkus Armbruster     sysbus_realize_and_unref(s, &error_fatal);
9573eddc1beSBharat Bhushan     memory_region_add_subregion(ccsr_addr_space, MPC8544_UTIL_OFFSET,
958dffb1dc2SBharat Bhushan                                 sysbus_mmio_get_region(s, 0));
959b0fb8423SAlexander Graf 
9601db09b84Saurel32     /* PCI */
9613e80f690SMarkus Armbruster     dev = qdev_new("e500-pcihost");
962d2623129SMarkus Armbruster     object_property_add_child(qdev_get_machine(), "pci-host", OBJECT(dev));
96303f04809SIgor Mammedov     qdev_prop_set_uint32(dev, "first_slot", pmc->pci_first_slot);
9643016dca0SBharat Bhushan     qdev_prop_set_uint32(dev, "first_pin_irq", pci_irq_nrs[0]);
965dffb1dc2SBharat Bhushan     s = SYS_BUS_DEVICE(dev);
9663c6ef471SMarkus Armbruster     sysbus_realize_and_unref(s, &error_fatal);
967d575a6ceSBharat Bhushan     for (i = 0; i < PCI_NUM_PINS; i++) {
968c91c187fSMichael Davidsaver         sysbus_connect_irq(s, i, qdev_get_gpio_in(mpicdev, pci_irq_nrs[i]));
969d575a6ceSBharat Bhushan     }
970d575a6ceSBharat Bhushan 
9713eddc1beSBharat Bhushan     memory_region_add_subregion(ccsr_addr_space, MPC8544_PCI_REGS_OFFSET,
972dffb1dc2SBharat Bhushan                                 sysbus_mmio_get_region(s, 0));
973dffb1dc2SBharat Bhushan 
974d461e3b9SAlexander Graf     pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
9751db09b84Saurel32     if (!pci_bus)
9761db09b84Saurel32         printf("couldn't create PCI controller!\n");
9771db09b84Saurel32 
9781db09b84Saurel32     if (pci_bus) {
9791db09b84Saurel32         /* Register network interfaces. */
9801db09b84Saurel32         for (i = 0; i < nb_nics; i++) {
98152310c3fSPaolo Bonzini             pci_nic_init_nofail(&nd_table[i], pci_bus, "virtio-net-pci", NULL);
9821db09b84Saurel32         }
9831db09b84Saurel32     }
9841db09b84Saurel32 
9855c145dacSAlexander Graf     /* Register spinning region */
98603f04809SIgor Mammedov     sysbus_create_simple("e500-spin", pmc->spin_base, NULL);
9875c145dacSAlexander Graf 
98803f04809SIgor Mammedov     if (pmc->has_mpc8xxx_gpio) {
989016f7758SAlexander Graf         qemu_irq poweroff_irq;
990016f7758SAlexander Graf 
9913e80f690SMarkus Armbruster         dev = qdev_new("mpc8xxx_gpio");
992b88e77f4SAlexander Graf         s = SYS_BUS_DEVICE(dev);
9933c6ef471SMarkus Armbruster         sysbus_realize_and_unref(s, &error_fatal);
994c91c187fSMichael Davidsaver         sysbus_connect_irq(s, 0, qdev_get_gpio_in(mpicdev, MPC8XXX_GPIO_IRQ));
995b88e77f4SAlexander Graf         memory_region_add_subregion(ccsr_addr_space, MPC8XXX_GPIO_OFFSET,
996b88e77f4SAlexander Graf                                     sysbus_mmio_get_region(s, 0));
997016f7758SAlexander Graf 
998016f7758SAlexander Graf         /* Power Off GPIO at Pin 0 */
999016f7758SAlexander Graf         poweroff_irq = qemu_allocate_irq(ppce500_power_off, NULL, 0);
1000016f7758SAlexander Graf         qdev_connect_gpio_out(dev, 0, poweroff_irq);
1001b88e77f4SAlexander Graf     }
1002b88e77f4SAlexander Graf 
1003f7087343SAlexander Graf     /* Platform Bus Device */
100403f04809SIgor Mammedov     if (pmc->has_platform_bus) {
10053e80f690SMarkus Armbruster         dev = qdev_new(TYPE_PLATFORM_BUS_DEVICE);
1006f7087343SAlexander Graf         dev->id = TYPE_PLATFORM_BUS_DEVICE;
100703f04809SIgor Mammedov         qdev_prop_set_uint32(dev, "num_irqs", pmc->platform_bus_num_irqs);
100803f04809SIgor Mammedov         qdev_prop_set_uint32(dev, "mmio_size", pmc->platform_bus_size);
10093c6ef471SMarkus Armbruster         sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
1010a3fc8396SIgor Mammedov         pms->pbus_dev = PLATFORM_BUS_DEVICE(dev);
1011f7087343SAlexander Graf 
1012a3fc8396SIgor Mammedov         s = SYS_BUS_DEVICE(pms->pbus_dev);
101303f04809SIgor Mammedov         for (i = 0; i < pmc->platform_bus_num_irqs; i++) {
101403f04809SIgor Mammedov             int irqn = pmc->platform_bus_first_irq + i;
1015c91c187fSMichael Davidsaver             sysbus_connect_irq(s, i, qdev_get_gpio_in(mpicdev, irqn));
1016f7087343SAlexander Graf         }
1017f7087343SAlexander Graf 
1018f7087343SAlexander Graf         memory_region_add_subregion(address_space_mem,
101903f04809SIgor Mammedov                                     pmc->platform_bus_base,
1020f7087343SAlexander Graf                                     sysbus_mmio_get_region(s, 0));
1021f7087343SAlexander Graf     }
1022f7087343SAlexander Graf 
10238d622594SDavid Engraf     /*
10248d622594SDavid Engraf      * Smart firmware defaults ahead!
10258d622594SDavid Engraf      *
10268d622594SDavid Engraf      * We follow the following table to select which payload we execute.
10278d622594SDavid Engraf      *
10288d622594SDavid Engraf      *  -kernel | -bios | payload
10298d622594SDavid Engraf      * ---------+-------+---------
10308d622594SDavid Engraf      *     N    |   Y   | u-boot
10318d622594SDavid Engraf      *     N    |   N   | u-boot
10328d622594SDavid Engraf      *     Y    |   Y   | u-boot
10338d622594SDavid Engraf      *     Y    |   N   | kernel
10348d622594SDavid Engraf      *
10358d622594SDavid Engraf      * This ensures backwards compatibility with how we used to expose
10368d622594SDavid Engraf      * -kernel to users but allows them to run through u-boot as well.
10378d622594SDavid Engraf      */
10388d622594SDavid Engraf     kernel_as_payload = false;
1039cd7b9498SPaolo Bonzini     if (machine->firmware == NULL) {
10403ef96221SMarcel Apfelbaum         if (machine->kernel_filename) {
10418d622594SDavid Engraf             payload_name = machine->kernel_filename;
10428d622594SDavid Engraf             kernel_as_payload = true;
10438d622594SDavid Engraf         } else {
10448d622594SDavid Engraf             payload_name = "u-boot.e500";
10458d622594SDavid Engraf         }
10468d622594SDavid Engraf     } else {
1047cd7b9498SPaolo Bonzini         payload_name = machine->firmware;
10488d622594SDavid Engraf     }
10498d622594SDavid Engraf 
10508d622594SDavid Engraf     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, payload_name);
10513b4f50bdSPeter Maydell     if (!filename) {
10523b4f50bdSPeter Maydell         error_report("could not find firmware/kernel file '%s'", payload_name);
10533b4f50bdSPeter Maydell         exit(1);
10543b4f50bdSPeter Maydell     }
10558d622594SDavid Engraf 
10564366e1dbSLiam Merwick     payload_size = load_elf(filename, NULL, NULL, NULL,
10576cdda0ffSAleksandar Markovic                             &bios_entry, &loadaddr, NULL, NULL,
10588d622594SDavid Engraf                             1, PPC_ELF_MACHINE, 0, 0);
10598d622594SDavid Engraf     if (payload_size < 0) {
10608d622594SDavid Engraf         /*
10618d622594SDavid Engraf          * Hrm. No ELF image? Try a uImage, maybe someone is giving us an
10628d622594SDavid Engraf          * ePAPR compliant kernel
10638d622594SDavid Engraf          */
1064f831f955SNick Hudson         loadaddr = LOAD_UIMAGE_LOADADDR_INVALID;
10658d622594SDavid Engraf         payload_size = load_uimage(filename, &bios_entry, &loadaddr, NULL,
10668d622594SDavid Engraf                                    NULL, NULL);
10678d622594SDavid Engraf         if (payload_size < 0) {
1068371b74e2SMao Zhongyi             error_report("could not load firmware '%s'", filename);
10698d622594SDavid Engraf             exit(1);
10708d622594SDavid Engraf         }
10718d622594SDavid Engraf     }
10728d622594SDavid Engraf 
10738d622594SDavid Engraf     g_free(filename);
10748d622594SDavid Engraf 
10758d622594SDavid Engraf     if (kernel_as_payload) {
10768d622594SDavid Engraf         kernel_base = loadaddr;
10778d622594SDavid Engraf         kernel_size = payload_size;
10788d622594SDavid Engraf     }
10798d622594SDavid Engraf 
10808d622594SDavid Engraf     cur_base = loadaddr + payload_size;
1081ab3dd749SPhilippe Mathieu-Daudé     if (cur_base < 32 * MiB) {
1082b4a5f24aSDavid Engraf         /* u-boot occupies memory up to 32MB, so load blobs above */
1083ab3dd749SPhilippe Mathieu-Daudé         cur_base = 32 * MiB;
1084b4a5f24aSDavid Engraf     }
10858d622594SDavid Engraf 
10868d622594SDavid Engraf     /* Load bare kernel only if no bios/u-boot has been provided */
10878d622594SDavid Engraf     if (machine->kernel_filename && !kernel_as_payload) {
10883812c71fSAlexander Graf         kernel_base = cur_base;
10893812c71fSAlexander Graf         kernel_size = load_image_targphys(machine->kernel_filename,
10903812c71fSAlexander Graf                                           cur_base,
10913538e846SIgor Mammedov                                           machine->ram_size - cur_base);
10921db09b84Saurel32         if (kernel_size < 0) {
10936f76b817SAlistair Francis             error_report("could not load kernel '%s'",
10943ef96221SMarcel Apfelbaum                          machine->kernel_filename);
10951db09b84Saurel32             exit(1);
10961db09b84Saurel32         }
1097528e536eSAlexander Graf 
10983812c71fSAlexander Graf         cur_base += kernel_size;
10991db09b84Saurel32     }
11001db09b84Saurel32 
11011db09b84Saurel32     /* Load initrd. */
11023ef96221SMarcel Apfelbaum     if (machine->initrd_filename) {
1103528e536eSAlexander Graf         initrd_base = (cur_base + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK;
11043ef96221SMarcel Apfelbaum         initrd_size = load_image_targphys(machine->initrd_filename, initrd_base,
11053538e846SIgor Mammedov                                           machine->ram_size - initrd_base);
11061db09b84Saurel32 
11071db09b84Saurel32         if (initrd_size < 0) {
11086f76b817SAlistair Francis             error_report("could not load initial ram disk '%s'",
11093ef96221SMarcel Apfelbaum                          machine->initrd_filename);
11101db09b84Saurel32             exit(1);
11111db09b84Saurel32         }
1112528e536eSAlexander Graf 
1113528e536eSAlexander Graf         cur_base = initrd_base + initrd_size;
11141db09b84Saurel32     }
11151db09b84Saurel32 
11163812c71fSAlexander Graf     /*
11178d622594SDavid Engraf      * Reserve space for dtb behind the kernel image because Linux has a bug
11188d622594SDavid Engraf      * where it can only handle the dtb if it's within the first 64MB of where
11198d622594SDavid Engraf      * <kernel> starts. dtb cannot not reach initrd_base because INITRD_LOAD_PAD
11208d622594SDavid Engraf      * ensures enough space between kernel and initrd.
11213812c71fSAlexander Graf      */
11228d622594SDavid Engraf     dt_base = (loadaddr + payload_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
11233538e846SIgor Mammedov     if (dt_base + DTB_MAX_SIZE > machine->ram_size) {
1124371b74e2SMao Zhongyi             error_report("not enough memory for device tree");
11253812c71fSAlexander Graf             exit(1);
11263812c71fSAlexander Graf     }
11275c145dacSAlexander Graf 
112803f04809SIgor Mammedov     dt_size = ppce500_prep_device_tree(pms, dt_base,
1129903585deSAlexander Graf                                        initrd_base, initrd_size,
11303812c71fSAlexander Graf                                        kernel_base, kernel_size);
1131cba2026aSAlexander Graf     if (dt_size < 0) {
11326f76b817SAlistair Francis         error_report("couldn't load device tree");
11331db09b84Saurel32         exit(1);
11341db09b84Saurel32     }
1135b8dec144SAlexander Graf     assert(dt_size < DTB_MAX_SIZE);
11361db09b84Saurel32 
1137e61c36d5SAlexander Graf     boot_info = env->load_info;
11383812c71fSAlexander Graf     boot_info->entry = bios_entry;
11393b989d49SAlexander Graf     boot_info->dt_base = dt_base;
1140cba2026aSAlexander Graf     boot_info->dt_size = dt_size;
11411db09b84Saurel32 }
11423eddc1beSBharat Bhushan 
1143d0c2b0d0Sxiaoqiang zhao static void e500_ccsr_initfn(Object *obj)
11443eddc1beSBharat Bhushan {
1145d0c2b0d0Sxiaoqiang zhao     PPCE500CCSRState *ccsr = CCSR(obj);
1146d0c2b0d0Sxiaoqiang zhao     memory_region_init(&ccsr->ccsr_space, obj, "e500-ccsr",
11473eddc1beSBharat Bhushan                        MPC8544_CCSRBAR_SIZE);
11483eddc1beSBharat Bhushan }
11493eddc1beSBharat Bhushan 
11503eddc1beSBharat Bhushan static const TypeInfo e500_ccsr_info = {
11513eddc1beSBharat Bhushan     .name          = TYPE_CCSR,
11523eddc1beSBharat Bhushan     .parent        = TYPE_SYS_BUS_DEVICE,
11533eddc1beSBharat Bhushan     .instance_size = sizeof(PPCE500CCSRState),
1154d0c2b0d0Sxiaoqiang zhao     .instance_init = e500_ccsr_initfn,
11553eddc1beSBharat Bhushan };
11563eddc1beSBharat Bhushan 
115703f04809SIgor Mammedov static const TypeInfo ppce500_info = {
115803f04809SIgor Mammedov     .name          = TYPE_PPCE500_MACHINE,
115903f04809SIgor Mammedov     .parent        = TYPE_MACHINE,
116003f04809SIgor Mammedov     .abstract      = true,
1161a3fc8396SIgor Mammedov     .instance_size = sizeof(PPCE500MachineState),
116203f04809SIgor Mammedov     .class_size    = sizeof(PPCE500MachineClass),
116303f04809SIgor Mammedov };
116403f04809SIgor Mammedov 
11653eddc1beSBharat Bhushan static void e500_register_types(void)
11663eddc1beSBharat Bhushan {
11673eddc1beSBharat Bhushan     type_register_static(&e500_ccsr_info);
116803f04809SIgor Mammedov     type_register_static(&ppce500_info);
11693eddc1beSBharat Bhushan }
11703eddc1beSBharat Bhushan 
11713eddc1beSBharat Bhushan type_init(e500_register_types)
1172