xref: /qemu/hw/ppc/e500.c (revision fc524567087c2537b5103cdfc1d41e4f442892b6)
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"
182c65db5eSPaolo Bonzini #include "qemu/datadir.h"
19ab3dd749SPhilippe Mathieu-Daudé #include "qemu/units.h"
20c4b07531SJason A. Donenfeld #include "qemu/guest-random.h"
21*9c2ff9cdSPierrick Bouvier #include "exec/target_page.h"
22da34e65cSMarkus Armbruster #include "qapi/error.h"
23e6eaabebSScott Wood #include "e500.h"
243eddc1beSBharat Bhushan #include "e500-ccsr.h"
251422e32dSPaolo Bonzini #include "net/net.h"
261de7afc9SPaolo Bonzini #include "qemu/config-file.h"
2763e4bf8eSBernhard Beschow #include "hw/block/flash.h"
287e6b5497SBernhard Beschow #include "hw/char/serial-mm.h"
29a2cb15b0SMichael S. Tsirkin #include "hw/pci/pci.h"
3032cad1ffSPhilippe Mathieu-Daudé #include "system/block-backend-io.h"
3132cad1ffSPhilippe Mathieu-Daudé #include "system/system.h"
3232cad1ffSPhilippe Mathieu-Daudé #include "system/kvm.h"
3332cad1ffSPhilippe Mathieu-Daudé #include "system/reset.h"
3432cad1ffSPhilippe Mathieu-Daudé #include "system/runstate.h"
351db09b84Saurel32 #include "kvm_ppc.h"
3632cad1ffSPhilippe Mathieu-Daudé #include "system/device_tree.h"
370d09e41aSPaolo Bonzini #include "hw/ppc/openpic.h"
388d085cf0SMark Cave-Ayland #include "hw/ppc/openpic_kvm.h"
390d09e41aSPaolo Bonzini #include "hw/ppc/ppc.h"
40a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
414a18e7c9SScott Wood #include "hw/loader.h"
42ca20cf32SBlue Swirl #include "elf.h"
434a18e7c9SScott Wood #include "hw/sysbus.h"
441de7afc9SPaolo Bonzini #include "qemu/host-utils.h"
45922a01a0SMarkus Armbruster #include "qemu/option.h"
460d09e41aSPaolo Bonzini #include "hw/pci-host/ppce500.h"
47f7087343SAlexander Graf #include "qemu/error-report.h"
48f7087343SAlexander Graf #include "hw/platform-bus.h"
49fdfb7f2cSAlexander Graf #include "hw/net/fsl_etsec/etsec.h"
507abb479cSAndrew Randrianasulu #include "hw/i2c/i2c.h"
5164552b6bSMarkus Armbruster #include "hw/irq.h"
523f288c4bSPhilippe Mathieu-Daudé #include "hw/sd/sdhci.h"
533f288c4bSPhilippe Mathieu-Daudé #include "hw/misc/unimp.h"
541db09b84Saurel32 
55cefd3cdbSBharat Bhushan #define EPAPR_MAGIC                (0x45504150)
569dd5eba1SScott Wood #define DTC_LOAD_PAD               0x1800000
5775bb6589SLiu Yu #define DTC_PAD_MASK               0xFFFFF
58ab3dd749SPhilippe Mathieu-Daudé #define DTB_MAX_SIZE               (8 * MiB)
5975bb6589SLiu Yu #define INITRD_LOAD_PAD            0x2000000
6075bb6589SLiu Yu #define INITRD_PAD_MASK            0xFFFFFF
611db09b84Saurel32 
62ab3dd749SPhilippe Mathieu-Daudé #define RAM_SIZES_ALIGN            (64 * MiB)
631db09b84Saurel32 
64b3305981SScott Wood /* TODO: parameterize */
65ed2bc496SAlexander Graf #define MPC8544_CCSRBAR_SIZE       0x00100000ULL
66dffb1dc2SBharat Bhushan #define MPC8544_MPIC_REGS_OFFSET   0x40000ULL
67a911b7a9SAlexander Graf #define MPC8544_MSI_REGS_OFFSET   0x41600ULL
68dffb1dc2SBharat Bhushan #define MPC8544_SERIAL0_REGS_OFFSET 0x4500ULL
69dffb1dc2SBharat Bhushan #define MPC8544_SERIAL1_REGS_OFFSET 0x4600ULL
70dffb1dc2SBharat Bhushan #define MPC8544_PCI_REGS_OFFSET    0x8000ULL
71ed2bc496SAlexander Graf #define MPC8544_PCI_REGS_SIZE      0x1000ULL
723f288c4bSPhilippe Mathieu-Daudé #define MPC85XX_ESDHC_REGS_OFFSET  0x2e000ULL
733f288c4bSPhilippe Mathieu-Daudé #define MPC85XX_ESDHC_REGS_SIZE    0x1000ULL
74dffb1dc2SBharat Bhushan #define MPC8544_UTIL_OFFSET        0xe0000ULL
75b88e77f4SAlexander Graf #define MPC8XXX_GPIO_OFFSET        0x000FF000ULL
767abb479cSAndrew Randrianasulu #define MPC8544_I2C_REGS_OFFSET    0x3000ULL
7782e345f5SAmit Tomar #define MPC8XXX_GPIO_IRQ           47
787abb479cSAndrew Randrianasulu #define MPC8544_I2C_IRQ            43
793f288c4bSPhilippe Mathieu-Daudé #define MPC85XX_ESDHC_IRQ          72
807abb479cSAndrew Randrianasulu #define RTC_REGS_OFFSET            0x68
811db09b84Saurel32 
820c36ab71SBin Meng #define PLATFORM_CLK_FREQ_HZ       (400 * 1000 * 1000)
830c36ab71SBin Meng 
843b989d49SAlexander Graf struct boot_info
853b989d49SAlexander Graf {
863b989d49SAlexander Graf     uint32_t dt_base;
87cba2026aSAlexander Graf     uint32_t dt_size;
883b989d49SAlexander Graf     uint32_t entry;
893b989d49SAlexander Graf };
903b989d49SAlexander Graf 
pci_map_create(void * fdt,uint32_t mpic,int first_slot,int nr_slots,int * len)91347dd79dSAlexander Graf static uint32_t *pci_map_create(void *fdt, uint32_t mpic, int first_slot,
92347dd79dSAlexander Graf                                 int nr_slots, int *len)
930dbc0798SAlexander Graf {
94347dd79dSAlexander Graf     int i = 0;
95347dd79dSAlexander Graf     int slot;
96347dd79dSAlexander Graf     int pci_irq;
979e2c1298SAlexander Graf     int host_irq;
98347dd79dSAlexander Graf     int last_slot = first_slot + nr_slots;
99347dd79dSAlexander Graf     uint32_t *pci_map;
1000dbc0798SAlexander Graf 
101347dd79dSAlexander Graf     *len = nr_slots * 4 * 7 * sizeof(uint32_t);
102347dd79dSAlexander Graf     pci_map = g_malloc(*len);
103347dd79dSAlexander Graf 
104347dd79dSAlexander Graf     for (slot = first_slot; slot < last_slot; slot++) {
105347dd79dSAlexander Graf         for (pci_irq = 0; pci_irq < 4; pci_irq++) {
106347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(slot << 11);
107347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(0x0);
108347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(0x0);
109347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(pci_irq + 1);
110347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(mpic);
1119e2c1298SAlexander Graf             host_irq = ppce500_pci_map_irq_slot(slot, pci_irq);
1129e2c1298SAlexander Graf             pci_map[i++] = cpu_to_be32(host_irq + 1);
113347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(0x1);
1140dbc0798SAlexander Graf         }
1150dbc0798SAlexander Graf     }
1160dbc0798SAlexander Graf 
117347dd79dSAlexander Graf     assert((i * sizeof(uint32_t)) == *len);
118347dd79dSAlexander Graf 
119347dd79dSAlexander Graf     return pci_map;
120347dd79dSAlexander Graf }
121347dd79dSAlexander Graf 
dt_serial_create(void * fdt,unsigned long long offset,const char * soc,const char * mpic,const char * alias,int idx,bool defcon)122a053a7ceSAlexander Graf static void dt_serial_create(void *fdt, unsigned long long offset,
123a053a7ceSAlexander Graf                              const char *soc, const char *mpic,
124a053a7ceSAlexander Graf                              const char *alias, int idx, bool defcon)
125a053a7ceSAlexander Graf {
1262fb513d3SGreg Kurz     char *ser;
127a053a7ceSAlexander Graf 
1282fb513d3SGreg Kurz     ser = g_strdup_printf("%s/serial@%llx", soc, offset);
1295a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, ser);
1305a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, ser, "device_type", "serial");
1315a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, ser, "compatible", "ns16550");
1325a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, ser, "reg", offset, 0x100);
1335a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, ser, "cell-index", idx);
13411dbcc70SBin Meng     qemu_fdt_setprop_cell(fdt, ser, "clock-frequency", PLATFORM_CLK_FREQ_HZ);
1355a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, ser, "interrupts", 42, 2);
1365a4348d1SPeter Crosthwaite     qemu_fdt_setprop_phandle(fdt, ser, "interrupt-parent", mpic);
1375a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, "/aliases", alias, ser);
138a053a7ceSAlexander Graf 
139a053a7ceSAlexander Graf     if (defcon) {
14090ee4e01SNikunj A Dadhania         /*
14190ee4e01SNikunj A Dadhania          * "linux,stdout-path" and "stdout" properties are deprecated by linux
14290ee4e01SNikunj A Dadhania          * kernel. New platforms should only use the "stdout-path" property. Set
14390ee4e01SNikunj A Dadhania          * the new property and continue using older property to remain
14490ee4e01SNikunj A Dadhania          * compatible with the existing firmware.
14590ee4e01SNikunj A Dadhania          */
1465a4348d1SPeter Crosthwaite         qemu_fdt_setprop_string(fdt, "/chosen", "linux,stdout-path", ser);
14790ee4e01SNikunj A Dadhania         qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", ser);
148a053a7ceSAlexander Graf     }
1492fb513d3SGreg Kurz     g_free(ser);
150a053a7ceSAlexander Graf }
151a053a7ceSAlexander Graf 
create_dt_mpc8xxx_gpio(void * fdt,const char * soc,const char * mpic)152b88e77f4SAlexander Graf static void create_dt_mpc8xxx_gpio(void *fdt, const char *soc, const char *mpic)
153b88e77f4SAlexander Graf {
154b88e77f4SAlexander Graf     hwaddr mmio0 = MPC8XXX_GPIO_OFFSET;
155b88e77f4SAlexander Graf     int irq0 = MPC8XXX_GPIO_IRQ;
156b88e77f4SAlexander Graf     gchar *node = g_strdup_printf("%s/gpio@%"PRIx64, soc, mmio0);
157016f7758SAlexander Graf     gchar *poweroff = g_strdup_printf("%s/power-off", soc);
158016f7758SAlexander Graf     int gpio_ph;
159b88e77f4SAlexander Graf 
160b88e77f4SAlexander Graf     qemu_fdt_add_subnode(fdt, node);
161b88e77f4SAlexander Graf     qemu_fdt_setprop_string(fdt, node, "compatible", "fsl,qoriq-gpio");
162b88e77f4SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "reg", mmio0, 0x1000);
163b88e77f4SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "interrupts", irq0, 0x2);
164b88e77f4SAlexander Graf     qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", mpic);
165b88e77f4SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "#gpio-cells", 2);
166b88e77f4SAlexander Graf     qemu_fdt_setprop(fdt, node, "gpio-controller", NULL, 0);
167016f7758SAlexander Graf     gpio_ph = qemu_fdt_alloc_phandle(fdt);
168016f7758SAlexander Graf     qemu_fdt_setprop_cell(fdt, node, "phandle", gpio_ph);
169016f7758SAlexander Graf     qemu_fdt_setprop_cell(fdt, node, "linux,phandle", gpio_ph);
170016f7758SAlexander Graf 
171016f7758SAlexander Graf     /* Power Off Pin */
172016f7758SAlexander Graf     qemu_fdt_add_subnode(fdt, poweroff);
173016f7758SAlexander Graf     qemu_fdt_setprop_string(fdt, poweroff, "compatible", "gpio-poweroff");
174016f7758SAlexander Graf     qemu_fdt_setprop_cells(fdt, poweroff, "gpios", gpio_ph, 0, 0);
175b88e77f4SAlexander Graf 
176b88e77f4SAlexander Graf     g_free(node);
177016f7758SAlexander Graf     g_free(poweroff);
178b88e77f4SAlexander Graf }
179b88e77f4SAlexander Graf 
dt_rtc_create(void * fdt,const char * i2c,const char * alias)1807abb479cSAndrew Randrianasulu static void dt_rtc_create(void *fdt, const char *i2c, const char *alias)
1817abb479cSAndrew Randrianasulu {
1827abb479cSAndrew Randrianasulu     int offset = RTC_REGS_OFFSET;
1837abb479cSAndrew Randrianasulu 
1847abb479cSAndrew Randrianasulu     gchar *rtc = g_strdup_printf("%s/rtc@%"PRIx32, i2c, offset);
1857abb479cSAndrew Randrianasulu     qemu_fdt_add_subnode(fdt, rtc);
1867abb479cSAndrew Randrianasulu     qemu_fdt_setprop_string(fdt, rtc, "compatible", "pericom,pt7c4338");
1877abb479cSAndrew Randrianasulu     qemu_fdt_setprop_cells(fdt, rtc, "reg", offset);
1887abb479cSAndrew Randrianasulu     qemu_fdt_setprop_string(fdt, "/aliases", alias, rtc);
1897abb479cSAndrew Randrianasulu 
1907abb479cSAndrew Randrianasulu     g_free(rtc);
1917abb479cSAndrew Randrianasulu }
1927abb479cSAndrew Randrianasulu 
dt_i2c_create(void * fdt,const char * soc,const char * mpic,const char * alias)1937abb479cSAndrew Randrianasulu static void dt_i2c_create(void *fdt, const char *soc, const char *mpic,
1947abb479cSAndrew Randrianasulu                              const char *alias)
1957abb479cSAndrew Randrianasulu {
1967abb479cSAndrew Randrianasulu     hwaddr mmio0 = MPC8544_I2C_REGS_OFFSET;
1977abb479cSAndrew Randrianasulu     int irq0 = MPC8544_I2C_IRQ;
1987abb479cSAndrew Randrianasulu 
1997abb479cSAndrew Randrianasulu     gchar *i2c = g_strdup_printf("%s/i2c@%"PRIx64, soc, mmio0);
2007abb479cSAndrew Randrianasulu     qemu_fdt_add_subnode(fdt, i2c);
2017abb479cSAndrew Randrianasulu     qemu_fdt_setprop_string(fdt, i2c, "device_type", "i2c");
2027abb479cSAndrew Randrianasulu     qemu_fdt_setprop_string(fdt, i2c, "compatible", "fsl-i2c");
2037abb479cSAndrew Randrianasulu     qemu_fdt_setprop_cells(fdt, i2c, "reg", mmio0, 0x14);
2047abb479cSAndrew Randrianasulu     qemu_fdt_setprop_cells(fdt, i2c, "cell-index", 0);
2057abb479cSAndrew Randrianasulu     qemu_fdt_setprop_cells(fdt, i2c, "interrupts", irq0, 0x2);
2067abb479cSAndrew Randrianasulu     qemu_fdt_setprop_phandle(fdt, i2c, "interrupt-parent", mpic);
207b5d65592SBernhard Beschow     qemu_fdt_setprop_cell(fdt, i2c, "#size-cells", 0);
208b5d65592SBernhard Beschow     qemu_fdt_setprop_cell(fdt, i2c, "#address-cells", 1);
2097abb479cSAndrew Randrianasulu     qemu_fdt_setprop_string(fdt, "/aliases", alias, i2c);
2107abb479cSAndrew Randrianasulu 
2117abb479cSAndrew Randrianasulu     g_free(i2c);
2127abb479cSAndrew Randrianasulu }
2137abb479cSAndrew Randrianasulu 
dt_sdhc_create(void * fdt,const char * parent,const char * mpic)2143f288c4bSPhilippe Mathieu-Daudé static void dt_sdhc_create(void *fdt, const char *parent, const char *mpic)
2153f288c4bSPhilippe Mathieu-Daudé {
2163f288c4bSPhilippe Mathieu-Daudé     hwaddr mmio = MPC85XX_ESDHC_REGS_OFFSET;
2173f288c4bSPhilippe Mathieu-Daudé     hwaddr size = MPC85XX_ESDHC_REGS_SIZE;
2183f288c4bSPhilippe Mathieu-Daudé     int irq = MPC85XX_ESDHC_IRQ;
2193f288c4bSPhilippe Mathieu-Daudé     g_autofree char *name = NULL;
2203f288c4bSPhilippe Mathieu-Daudé 
2213f288c4bSPhilippe Mathieu-Daudé     name = g_strdup_printf("%s/sdhc@%" PRIx64, parent, mmio);
2223f288c4bSPhilippe Mathieu-Daudé     qemu_fdt_add_subnode(fdt, name);
2233f288c4bSPhilippe Mathieu-Daudé     qemu_fdt_setprop(fdt, name, "sdhci,auto-cmd12", NULL, 0);
2243f288c4bSPhilippe Mathieu-Daudé     qemu_fdt_setprop_phandle(fdt, name, "interrupt-parent", mpic);
2253f288c4bSPhilippe Mathieu-Daudé     qemu_fdt_setprop_cells(fdt, name, "bus-width", 4);
2263f288c4bSPhilippe Mathieu-Daudé     qemu_fdt_setprop_cells(fdt, name, "interrupts", irq, 0x2);
2273f288c4bSPhilippe Mathieu-Daudé     qemu_fdt_setprop_cells(fdt, name, "reg", mmio, size);
2283f288c4bSPhilippe Mathieu-Daudé     qemu_fdt_setprop_string(fdt, name, "compatible", "fsl,esdhc");
2293f288c4bSPhilippe Mathieu-Daudé }
2307abb479cSAndrew Randrianasulu 
231f7087343SAlexander Graf typedef struct PlatformDevtreeData {
232f7087343SAlexander Graf     void *fdt;
233f7087343SAlexander Graf     const char *mpic;
234f7087343SAlexander Graf     int irq_start;
235f7087343SAlexander Graf     const char *node;
236f7087343SAlexander Graf     PlatformBusDevice *pbus;
237f7087343SAlexander Graf } PlatformDevtreeData;
238f7087343SAlexander Graf 
create_devtree_etsec(SysBusDevice * sbdev,PlatformDevtreeData * data)239fdfb7f2cSAlexander Graf static int create_devtree_etsec(SysBusDevice *sbdev, PlatformDevtreeData *data)
240fdfb7f2cSAlexander Graf {
241fdfb7f2cSAlexander Graf     eTSEC *etsec = ETSEC_COMMON(sbdev);
242fdfb7f2cSAlexander Graf     PlatformBusDevice *pbus = data->pbus;
243fdfb7f2cSAlexander Graf     hwaddr mmio0 = platform_bus_get_mmio_addr(pbus, sbdev, 0);
244fdfb7f2cSAlexander Graf     int irq0 = platform_bus_get_irqn(pbus, sbdev, 0);
245fdfb7f2cSAlexander Graf     int irq1 = platform_bus_get_irqn(pbus, sbdev, 1);
246fdfb7f2cSAlexander Graf     int irq2 = platform_bus_get_irqn(pbus, sbdev, 2);
2474348a3afSBernhard Beschow     gchar *node = g_strdup_printf("%s/ethernet@%"PRIx64, data->node, mmio0);
248fdfb7f2cSAlexander Graf     gchar *group = g_strdup_printf("%s/queue-group", node);
249fdfb7f2cSAlexander Graf     void *fdt = data->fdt;
250fdfb7f2cSAlexander Graf 
251fdfb7f2cSAlexander Graf     assert((int64_t)mmio0 >= 0);
252fdfb7f2cSAlexander Graf     assert(irq0 >= 0);
253fdfb7f2cSAlexander Graf     assert(irq1 >= 0);
254fdfb7f2cSAlexander Graf     assert(irq2 >= 0);
255fdfb7f2cSAlexander Graf 
256fdfb7f2cSAlexander Graf     qemu_fdt_add_subnode(fdt, node);
257e5943b00SBin Meng     qemu_fdt_setprop(fdt, node, "ranges", NULL, 0);
258fdfb7f2cSAlexander Graf     qemu_fdt_setprop_string(fdt, node, "device_type", "network");
259fdfb7f2cSAlexander Graf     qemu_fdt_setprop_string(fdt, node, "compatible", "fsl,etsec2");
260fdfb7f2cSAlexander Graf     qemu_fdt_setprop_string(fdt, node, "model", "eTSEC");
261fdfb7f2cSAlexander Graf     qemu_fdt_setprop(fdt, node, "local-mac-address", etsec->conf.macaddr.a, 6);
262fdfb7f2cSAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "fixed-link", 0, 1, 1000, 0, 0);
26309325678SBin Meng     qemu_fdt_setprop_cells(fdt, node, "#size-cells", 1);
26409325678SBin Meng     qemu_fdt_setprop_cells(fdt, node, "#address-cells", 1);
265fdfb7f2cSAlexander Graf 
266fdfb7f2cSAlexander Graf     qemu_fdt_add_subnode(fdt, group);
267fdfb7f2cSAlexander Graf     qemu_fdt_setprop_cells(fdt, group, "reg", mmio0, 0x1000);
268fdfb7f2cSAlexander Graf     qemu_fdt_setprop_cells(fdt, group, "interrupts",
269fdfb7f2cSAlexander Graf         data->irq_start + irq0, 0x2,
270fdfb7f2cSAlexander Graf         data->irq_start + irq1, 0x2,
271fdfb7f2cSAlexander Graf         data->irq_start + irq2, 0x2);
272fdfb7f2cSAlexander Graf 
273fdfb7f2cSAlexander Graf     g_free(node);
274fdfb7f2cSAlexander Graf     g_free(group);
275fdfb7f2cSAlexander Graf 
276fdfb7f2cSAlexander Graf     return 0;
277fdfb7f2cSAlexander Graf }
278fdfb7f2cSAlexander Graf 
sysbus_device_create_devtree(SysBusDevice * sbdev,void * opaque)2794f01a637SDavid Gibson static void sysbus_device_create_devtree(SysBusDevice *sbdev, void *opaque)
280f7087343SAlexander Graf {
281f7087343SAlexander Graf     PlatformDevtreeData *data = opaque;
282f7087343SAlexander Graf     bool matched = false;
283f7087343SAlexander Graf 
284fdfb7f2cSAlexander Graf     if (object_dynamic_cast(OBJECT(sbdev), TYPE_ETSEC_COMMON)) {
285fdfb7f2cSAlexander Graf         create_devtree_etsec(sbdev, data);
286fdfb7f2cSAlexander Graf         matched = true;
287fdfb7f2cSAlexander Graf     }
288fdfb7f2cSAlexander Graf 
289f7087343SAlexander Graf     if (!matched) {
290f7087343SAlexander Graf         error_report("Device %s is not supported by this machine yet.",
291f7087343SAlexander Graf                      qdev_fw_name(DEVICE(sbdev)));
292f7087343SAlexander Graf         exit(1);
293f7087343SAlexander Graf     }
294f7087343SAlexander Graf }
295f7087343SAlexander Graf 
create_devtree_flash(SysBusDevice * sbdev,PlatformDevtreeData * data)29663e4bf8eSBernhard Beschow static void create_devtree_flash(SysBusDevice *sbdev,
29763e4bf8eSBernhard Beschow                                  PlatformDevtreeData *data)
29863e4bf8eSBernhard Beschow {
29963e4bf8eSBernhard Beschow     g_autofree char *name = NULL;
30063e4bf8eSBernhard Beschow     uint64_t num_blocks = object_property_get_uint(OBJECT(sbdev),
30163e4bf8eSBernhard Beschow                                                    "num-blocks",
30263e4bf8eSBernhard Beschow                                                    &error_fatal);
30363e4bf8eSBernhard Beschow     uint64_t sector_length = object_property_get_uint(OBJECT(sbdev),
30463e4bf8eSBernhard Beschow                                                       "sector-length",
30563e4bf8eSBernhard Beschow                                                       &error_fatal);
30663e4bf8eSBernhard Beschow     uint64_t bank_width = object_property_get_uint(OBJECT(sbdev),
30763e4bf8eSBernhard Beschow                                                    "width",
30863e4bf8eSBernhard Beschow                                                    &error_fatal);
30963e4bf8eSBernhard Beschow     hwaddr flashbase = 0;
31063e4bf8eSBernhard Beschow     hwaddr flashsize = num_blocks * sector_length;
31163e4bf8eSBernhard Beschow     void *fdt = data->fdt;
31263e4bf8eSBernhard Beschow 
31363e4bf8eSBernhard Beschow     name = g_strdup_printf("%s/nor@%" PRIx64, data->node, flashbase);
31463e4bf8eSBernhard Beschow     qemu_fdt_add_subnode(fdt, name);
31563e4bf8eSBernhard Beschow     qemu_fdt_setprop_string(fdt, name, "compatible", "cfi-flash");
31663e4bf8eSBernhard Beschow     qemu_fdt_setprop_sized_cells(fdt, name, "reg",
31763e4bf8eSBernhard Beschow                                  1, flashbase, 1, flashsize);
31863e4bf8eSBernhard Beschow     qemu_fdt_setprop_cell(fdt, name, "bank-width", bank_width);
31963e4bf8eSBernhard Beschow }
32063e4bf8eSBernhard Beschow 
platform_bus_create_devtree(PPCE500MachineState * pms,void * fdt,const char * mpic)321a3fc8396SIgor Mammedov static void platform_bus_create_devtree(PPCE500MachineState *pms,
32203f04809SIgor Mammedov                                         void *fdt, const char *mpic)
323f7087343SAlexander Graf {
324a3fc8396SIgor Mammedov     const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(pms);
32503f04809SIgor Mammedov     gchar *node = g_strdup_printf("/platform@%"PRIx64, pmc->platform_bus_base);
326f7087343SAlexander Graf     const char platcomp[] = "qemu,platform\0simple-bus";
32703f04809SIgor Mammedov     uint64_t addr = pmc->platform_bus_base;
32803f04809SIgor Mammedov     uint64_t size = pmc->platform_bus_size;
32903f04809SIgor Mammedov     int irq_start = pmc->platform_bus_first_irq;
33063e4bf8eSBernhard Beschow     SysBusDevice *sbdev;
33163e4bf8eSBernhard Beschow     bool ambiguous;
332f7087343SAlexander Graf 
333f7087343SAlexander Graf     /* Create a /platform node that we can put all devices into */
334f7087343SAlexander Graf 
335f7087343SAlexander Graf     qemu_fdt_add_subnode(fdt, node);
336f7087343SAlexander Graf     qemu_fdt_setprop(fdt, node, "compatible", platcomp, sizeof(platcomp));
337f7087343SAlexander Graf 
338f7087343SAlexander Graf     /* Our platform bus region is less than 32bit big, so 1 cell is enough for
339f7087343SAlexander Graf        address and size */
340f7087343SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "#size-cells", 1);
341f7087343SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "#address-cells", 1);
342f7087343SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "ranges", 0, addr >> 32, addr, size);
343f7087343SAlexander Graf 
344f7087343SAlexander Graf     qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", mpic);
345f7087343SAlexander Graf 
346a3fc8396SIgor Mammedov     /* Create dt nodes for dynamic devices */
347f7087343SAlexander Graf     PlatformDevtreeData data = {
348f7087343SAlexander Graf         .fdt = fdt,
349f7087343SAlexander Graf         .mpic = mpic,
350f7087343SAlexander Graf         .irq_start = irq_start,
351f7087343SAlexander Graf         .node = node,
352a3fc8396SIgor Mammedov         .pbus = pms->pbus_dev,
353f7087343SAlexander Graf     };
354f7087343SAlexander Graf 
355f7087343SAlexander Graf     /* Loop through all dynamic sysbus devices and create nodes for them */
356f7087343SAlexander Graf     foreach_dynamic_sysbus_device(sysbus_device_create_devtree, &data);
357f7087343SAlexander Graf 
35863e4bf8eSBernhard Beschow     sbdev = SYS_BUS_DEVICE(object_resolve_path_type("", TYPE_PFLASH_CFI01,
35963e4bf8eSBernhard Beschow                                                     &ambiguous));
36063e4bf8eSBernhard Beschow     if (sbdev) {
36163e4bf8eSBernhard Beschow         assert(!ambiguous);
36263e4bf8eSBernhard Beschow         create_devtree_flash(sbdev, &data);
36363e4bf8eSBernhard Beschow     }
36463e4bf8eSBernhard Beschow 
365f7087343SAlexander Graf     g_free(node);
366f7087343SAlexander Graf }
367f7087343SAlexander Graf 
ppce500_load_device_tree(PPCE500MachineState * pms,hwaddr addr,hwaddr initrd_base,hwaddr initrd_size,hwaddr kernel_base,hwaddr kernel_size,bool dry_run)36803f04809SIgor Mammedov static int ppce500_load_device_tree(PPCE500MachineState *pms,
369a8170e5eSAvi Kivity                                     hwaddr addr,
370a8170e5eSAvi Kivity                                     hwaddr initrd_base,
37128290f37SAlexander Graf                                     hwaddr initrd_size,
372903585deSAlexander Graf                                     hwaddr kernel_base,
373903585deSAlexander Graf                                     hwaddr kernel_size,
37428290f37SAlexander Graf                                     bool dry_run)
3751db09b84Saurel32 {
37603f04809SIgor Mammedov     MachineState *machine = MACHINE(pms);
377fe6b6346SLike Xu     unsigned int smp_cpus = machine->smp.cpus;
37803f04809SIgor Mammedov     const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(pms);
379b77af26eSRichard Henderson     CPUPPCState *env = cpu_env(first_cpu);
380dbf916d8SAurelien Jarno     int ret = -1;
3813ef96221SMarcel Apfelbaum     uint64_t mem_reg_property[] = { 0, cpu_to_be64(machine->ram_size) };
3827ec632b4Spbrook     int fdt_size;
383dbf916d8SAurelien Jarno     void *fdt;
3845de6b46dSAlexander Graf     uint8_t hypercall[16];
3850c36ab71SBin Meng     uint32_t clock_freq = PLATFORM_CLK_FREQ_HZ;
3860c36ab71SBin Meng     uint32_t tb_freq = PLATFORM_CLK_FREQ_HZ;
387621d05e3SAlexander Graf     int i;
388ebb9518aSAlexander Graf     char compatible_sb[] = "fsl,mpc8544-immr\0simple-bus";
3892fb513d3SGreg Kurz     char *soc;
3902fb513d3SGreg Kurz     char *mpic;
39119ac9deaSAlexander Graf     uint32_t mpic_ph;
392a911b7a9SAlexander Graf     uint32_t msi_ph;
3932fb513d3SGreg Kurz     char *gutil;
3942fb513d3SGreg Kurz     char *pci;
3952fb513d3SGreg Kurz     char *msi;
396347dd79dSAlexander Graf     uint32_t *pci_map = NULL;
397347dd79dSAlexander Graf     int len;
3983627757eSAlexander Graf     uint32_t pci_ranges[14] =
3993627757eSAlexander Graf         {
40003f04809SIgor Mammedov             0x2000000, 0x0, pmc->pci_mmio_bus_base,
40103f04809SIgor Mammedov             pmc->pci_mmio_base >> 32, pmc->pci_mmio_base,
4023627757eSAlexander Graf             0x0, 0x20000000,
4033627757eSAlexander Graf 
4043627757eSAlexander Graf             0x1000000, 0x0, 0x0,
40503f04809SIgor Mammedov             pmc->pci_pio_base >> 32, pmc->pci_pio_base,
4063627757eSAlexander Graf             0x0, 0x10000,
4073627757eSAlexander Graf         };
408f2ce39b4SPaolo Bonzini     const char *dtb_file = machine->dtb;
409f2ce39b4SPaolo Bonzini     const char *toplevel_compat = machine->dt_compatible;
410c4b07531SJason A. Donenfeld     uint8_t rng_seed[32];
411d1b93565SAlexander Graf 
412d1b93565SAlexander Graf     if (dtb_file) {
413d1b93565SAlexander Graf         char *filename;
414d1b93565SAlexander Graf         filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_file);
415d1b93565SAlexander Graf         if (!filename) {
416d1b93565SAlexander Graf             goto out;
417d1b93565SAlexander Graf         }
418d1b93565SAlexander Graf 
419d1b93565SAlexander Graf         fdt = load_device_tree(filename, &fdt_size);
4202343dd11SMichael Tokarev         g_free(filename);
421d1b93565SAlexander Graf         if (!fdt) {
422d1b93565SAlexander Graf             goto out;
423d1b93565SAlexander Graf         }
424d1b93565SAlexander Graf         goto done;
425d1b93565SAlexander Graf     }
4261db09b84Saurel32 
4272636fcb6SAlexander Graf     fdt = create_device_tree(&fdt_size);
4285cea8590SPaul Brook     if (fdt == NULL) {
4295cea8590SPaul Brook         goto out;
4305cea8590SPaul Brook     }
4311db09b84Saurel32 
4321db09b84Saurel32     /* Manipulate device tree in memory. */
4335a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 2);
4345a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 2);
43551b852b7SAlexander Graf 
4365a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, "/memory");
4375a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, "/memory", "device_type", "memory");
4385a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, "/memory", "reg", mem_reg_property,
4391db09b84Saurel32                      sizeof(mem_reg_property));
4401db09b84Saurel32 
4415a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, "/chosen");
4423b989d49SAlexander Graf     if (initrd_size) {
4435a4348d1SPeter Crosthwaite         ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start",
4441db09b84Saurel32                                     initrd_base);
4453b989d49SAlexander Graf         if (ret < 0) {
4461db09b84Saurel32             fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
4473b989d49SAlexander Graf         }
4481db09b84Saurel32 
4495a4348d1SPeter Crosthwaite         ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
4501db09b84Saurel32                                     (initrd_base + initrd_size));
4513b989d49SAlexander Graf         if (ret < 0) {
4521db09b84Saurel32             fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
4533b989d49SAlexander Graf         }
454903585deSAlexander Graf 
455903585deSAlexander Graf     }
456903585deSAlexander Graf 
457903585deSAlexander Graf     if (kernel_base != -1ULL) {
458903585deSAlexander Graf         qemu_fdt_setprop_cells(fdt, "/chosen", "qemu,boot-kernel",
459903585deSAlexander Graf                                      kernel_base >> 32, kernel_base,
460903585deSAlexander Graf                                      kernel_size >> 32, kernel_size);
4613b989d49SAlexander Graf     }
4621db09b84Saurel32 
4635a4348d1SPeter Crosthwaite     ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
4643ef96221SMarcel Apfelbaum                                       machine->kernel_cmdline);
4651db09b84Saurel32     if (ret < 0)
4661db09b84Saurel32         fprintf(stderr, "couldn't set /chosen/bootargs\n");
4671db09b84Saurel32 
468c4b07531SJason A. Donenfeld     qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed));
469c4b07531SJason A. Donenfeld     qemu_fdt_setprop(fdt, "/chosen", "rng-seed", rng_seed, sizeof(rng_seed));
470c4b07531SJason A. Donenfeld 
4711db09b84Saurel32     if (kvm_enabled()) {
472911d6e7aSAlexander Graf         /* Read out host's frequencies */
473911d6e7aSAlexander Graf         clock_freq = kvmppc_get_clockfreq();
474911d6e7aSAlexander Graf         tb_freq = kvmppc_get_tbfreq();
4755de6b46dSAlexander Graf 
4765de6b46dSAlexander Graf         /* indicate KVM hypercall interface */
4775a4348d1SPeter Crosthwaite         qemu_fdt_add_subnode(fdt, "/hypervisor");
4785a4348d1SPeter Crosthwaite         qemu_fdt_setprop_string(fdt, "/hypervisor", "compatible",
4795de6b46dSAlexander Graf                                 "linux,kvm");
4805de6b46dSAlexander Graf         kvmppc_get_hypercall(env, hypercall, sizeof(hypercall));
4815a4348d1SPeter Crosthwaite         qemu_fdt_setprop(fdt, "/hypervisor", "hcall-instructions",
4825de6b46dSAlexander Graf                          hypercall, sizeof(hypercall));
4831a61a9aeSStuart Yoder         /* if KVM supports the idle hcall, set property indicating this */
4841a61a9aeSStuart Yoder         if (kvmppc_get_hasidle(env)) {
4855a4348d1SPeter Crosthwaite             qemu_fdt_setprop(fdt, "/hypervisor", "has-idle", NULL, 0);
4861a61a9aeSStuart Yoder         }
4871db09b84Saurel32     }
4881db09b84Saurel32 
489625e665bSAlexander Graf     /* Create CPU nodes */
4905a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, "/cpus");
4915a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 1);
4925a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0);
493625e665bSAlexander Graf 
4941e3debf0SAlexander Graf     /* We need to generate the cpu nodes in reverse order, so Linux can pick
4951e3debf0SAlexander Graf        the first node as boot node and be happy */
4961e3debf0SAlexander Graf     for (i = smp_cpus - 1; i >= 0; i--) {
497440c8152SAndreas Färber         CPUState *cpu;
4982fb513d3SGreg Kurz         char *cpu_name;
49903f04809SIgor Mammedov         uint64_t cpu_release_addr = pmc->spin_base + (i * 0x20);
50010f25a46SAlexander Graf 
501440c8152SAndreas Färber         cpu = qemu_get_cpu(i);
50255e5c285SAndreas Färber         if (cpu == NULL) {
5031e3debf0SAlexander Graf             continue;
5041e3debf0SAlexander Graf         }
505b77af26eSRichard Henderson         env = cpu_env(cpu);
5061e3debf0SAlexander Graf 
5072fb513d3SGreg Kurz         cpu_name = g_strdup_printf("/cpus/PowerPC,8544@%x", i);
5085a4348d1SPeter Crosthwaite         qemu_fdt_add_subnode(fdt, cpu_name);
5095a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq);
5105a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq);
5115a4348d1SPeter Crosthwaite         qemu_fdt_setprop_string(fdt, cpu_name, "device_type", "cpu");
5126d536570SSam Bobroff         qemu_fdt_setprop_cell(fdt, cpu_name, "reg", i);
5135a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-line-size",
5141e3debf0SAlexander Graf                               env->dcache_line_size);
5155a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-line-size",
5161e3debf0SAlexander Graf                               env->icache_line_size);
5175a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-size", 0x8000);
5185a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-size", 0x8000);
5195a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "bus-frequency", 0);
52055e5c285SAndreas Färber         if (cpu->cpu_index) {
5215a4348d1SPeter Crosthwaite             qemu_fdt_setprop_string(fdt, cpu_name, "status", "disabled");
5225a4348d1SPeter Crosthwaite             qemu_fdt_setprop_string(fdt, cpu_name, "enable-method",
5235a4348d1SPeter Crosthwaite                                     "spin-table");
5245a4348d1SPeter Crosthwaite             qemu_fdt_setprop_u64(fdt, cpu_name, "cpu-release-addr",
5251d2e5c52SAlexander Graf                                  cpu_release_addr);
5261e3debf0SAlexander Graf         } else {
5275a4348d1SPeter Crosthwaite             qemu_fdt_setprop_string(fdt, cpu_name, "status", "okay");
5281e3debf0SAlexander Graf         }
5292fb513d3SGreg Kurz         g_free(cpu_name);
5301db09b84Saurel32     }
5311db09b84Saurel32 
5325a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, "/aliases");
5335da96624SAlexander Graf     /* XXX These should go into their respective devices' code */
5342fb513d3SGreg Kurz     soc = g_strdup_printf("/soc@%"PRIx64, pmc->ccsrbar_base);
5355a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, soc);
5365a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, soc, "device_type", "soc");
5375a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, soc, "compatible", compatible_sb,
538ebb9518aSAlexander Graf                      sizeof(compatible_sb));
5395a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, soc, "#address-cells", 1);
5405a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, soc, "#size-cells", 1);
5415a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, soc, "ranges", 0x0,
54203f04809SIgor Mammedov                            pmc->ccsrbar_base >> 32, pmc->ccsrbar_base,
5435da96624SAlexander Graf                            MPC8544_CCSRBAR_SIZE);
5445da96624SAlexander Graf     /* XXX should contain a reasonable value */
5455a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, soc, "bus-frequency", 0);
5465da96624SAlexander Graf 
5472fb513d3SGreg Kurz     mpic = g_strdup_printf("%s/pic@%llx", soc, MPC8544_MPIC_REGS_OFFSET);
5485a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, mpic);
5495a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, mpic, "device_type", "open-pic");
5505a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, mpic, "compatible", "fsl,mpic");
5515a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_OFFSET,
552dffb1dc2SBharat Bhushan                            0x40000);
5535a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, mpic, "#address-cells", 0);
5545a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, mpic, "#interrupt-cells", 2);
5555a4348d1SPeter Crosthwaite     mpic_ph = qemu_fdt_alloc_phandle(fdt);
5565a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, mpic, "phandle", mpic_ph);
5575a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, mpic, "linux,phandle", mpic_ph);
5585a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, mpic, "interrupt-controller", NULL, 0);
55919ac9deaSAlexander Graf 
5600cfc6e8dSAlexander Graf     /*
5610cfc6e8dSAlexander Graf      * We have to generate ser1 first, because Linux takes the first
5620cfc6e8dSAlexander Graf      * device it finds in the dt as serial output device. And we generate
5630cfc6e8dSAlexander Graf      * devices in reverse order to the dt.
5640cfc6e8dSAlexander Graf      */
5659bca0edbSPeter Maydell     if (serial_hd(1)) {
566dffb1dc2SBharat Bhushan         dt_serial_create(fdt, MPC8544_SERIAL1_REGS_OFFSET,
567a053a7ceSAlexander Graf                          soc, mpic, "serial1", 1, false);
56879c0ff2cSAlexander Graf     }
56979c0ff2cSAlexander Graf 
5709bca0edbSPeter Maydell     if (serial_hd(0)) {
571dffb1dc2SBharat Bhushan         dt_serial_create(fdt, MPC8544_SERIAL0_REGS_OFFSET,
572a053a7ceSAlexander Graf                          soc, mpic, "serial0", 0, true);
57379c0ff2cSAlexander Graf     }
5740cfc6e8dSAlexander Graf 
5757abb479cSAndrew Randrianasulu     /* i2c */
5767abb479cSAndrew Randrianasulu     dt_i2c_create(fdt, soc, mpic, "i2c");
5777abb479cSAndrew Randrianasulu 
5787abb479cSAndrew Randrianasulu     dt_rtc_create(fdt, "i2c", "rtc");
5797abb479cSAndrew Randrianasulu 
5803f288c4bSPhilippe Mathieu-Daudé     /* sdhc */
5813f288c4bSPhilippe Mathieu-Daudé     if (pmc->has_esdhc) {
5823f288c4bSPhilippe Mathieu-Daudé         dt_sdhc_create(fdt, soc, mpic);
5833f288c4bSPhilippe Mathieu-Daudé     }
5847abb479cSAndrew Randrianasulu 
5852fb513d3SGreg Kurz     gutil = g_strdup_printf("%s/global-utilities@%llx", soc,
586dffb1dc2SBharat Bhushan                             MPC8544_UTIL_OFFSET);
5875a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, gutil);
5885a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, gutil, "compatible", "fsl,mpc8544-guts");
5895a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, gutil, "reg", MPC8544_UTIL_OFFSET, 0x1000);
5905a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, gutil, "fsl,has-rstcr", NULL, 0);
5912fb513d3SGreg Kurz     g_free(gutil);
592f5038483SAlexander Graf 
5932fb513d3SGreg Kurz     msi = g_strdup_printf("/%s/msi@%llx", soc, MPC8544_MSI_REGS_OFFSET);
5945a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, msi);
5955a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, msi, "compatible", "fsl,mpic-msi");
5965a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, msi, "reg", MPC8544_MSI_REGS_OFFSET, 0x200);
5975a4348d1SPeter Crosthwaite     msi_ph = qemu_fdt_alloc_phandle(fdt);
5985a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, msi, "msi-available-ranges", 0x0, 0x100);
5995a4348d1SPeter Crosthwaite     qemu_fdt_setprop_phandle(fdt, msi, "interrupt-parent", mpic);
6005a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, msi, "interrupts",
601a911b7a9SAlexander Graf         0xe0, 0x0,
602a911b7a9SAlexander Graf         0xe1, 0x0,
603a911b7a9SAlexander Graf         0xe2, 0x0,
604a911b7a9SAlexander Graf         0xe3, 0x0,
605a911b7a9SAlexander Graf         0xe4, 0x0,
606a911b7a9SAlexander Graf         0xe5, 0x0,
607a911b7a9SAlexander Graf         0xe6, 0x0,
608a911b7a9SAlexander Graf         0xe7, 0x0);
6095a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, msi, "phandle", msi_ph);
6105a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, msi, "linux,phandle", msi_ph);
6112fb513d3SGreg Kurz     g_free(msi);
612a911b7a9SAlexander Graf 
6132fb513d3SGreg Kurz     pci = g_strdup_printf("/pci@%llx",
61403f04809SIgor Mammedov                           pmc->ccsrbar_base + MPC8544_PCI_REGS_OFFSET);
6155a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, pci);
6165a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "cell-index", 0);
6175a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, pci, "compatible", "fsl,mpc8540-pci");
6185a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, pci, "device_type", "pci");
6195a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, pci, "interrupt-map-mask", 0xf800, 0x0,
6200dbc0798SAlexander Graf                            0x0, 0x7);
6215a4348d1SPeter Crosthwaite     pci_map = pci_map_create(fdt, qemu_fdt_get_phandle(fdt, mpic),
62203f04809SIgor Mammedov                              pmc->pci_first_slot, pmc->pci_nr_slots,
623492ec48dSAlexander Graf                              &len);
6245a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, pci, "interrupt-map", pci_map, len);
6255a4348d1SPeter Crosthwaite     qemu_fdt_setprop_phandle(fdt, pci, "interrupt-parent", mpic);
6265a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, pci, "interrupts", 24, 2);
6275a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, pci, "bus-range", 0, 255);
6283627757eSAlexander Graf     for (i = 0; i < 14; i++) {
6290dbc0798SAlexander Graf         pci_ranges[i] = cpu_to_be32(pci_ranges[i]);
6300dbc0798SAlexander Graf     }
6315a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "fsl,msi", msi_ph);
6325a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, pci, "ranges", pci_ranges, sizeof(pci_ranges));
6332eaaac1fSAlexander Graf     qemu_fdt_setprop_cells(fdt, pci, "reg",
63403f04809SIgor Mammedov                            (pmc->ccsrbar_base + MPC8544_PCI_REGS_OFFSET) >> 32,
63503f04809SIgor Mammedov                            (pmc->ccsrbar_base + MPC8544_PCI_REGS_OFFSET),
6362eaaac1fSAlexander Graf                            0, 0x1000);
6375a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "clock-frequency", 66666666);
6385a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "#interrupt-cells", 1);
6395a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "#size-cells", 2);
6405a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "#address-cells", 3);
6415a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, "/aliases", "pci0", pci);
6422fb513d3SGreg Kurz     g_free(pci);
6430dbc0798SAlexander Graf 
64403f04809SIgor Mammedov     if (pmc->has_mpc8xxx_gpio) {
645b88e77f4SAlexander Graf         create_dt_mpc8xxx_gpio(fdt, soc, mpic);
646b88e77f4SAlexander Graf     }
6472fb513d3SGreg Kurz     g_free(soc);
648b88e77f4SAlexander Graf 
649a3fc8396SIgor Mammedov     platform_bus_create_devtree(pms, fdt, mpic);
6500998fcb3SBernhard Beschow 
6512fb513d3SGreg Kurz     g_free(mpic);
652f7087343SAlexander Graf 
65303f04809SIgor Mammedov     pmc->fixup_devtree(fdt);
654e6eaabebSScott Wood 
655e6eaabebSScott Wood     if (toplevel_compat) {
6565a4348d1SPeter Crosthwaite         qemu_fdt_setprop(fdt, "/", "compatible", toplevel_compat,
657e6eaabebSScott Wood                          strlen(toplevel_compat) + 1);
658e6eaabebSScott Wood     }
659e6eaabebSScott Wood 
660d1b93565SAlexander Graf done:
66128290f37SAlexander Graf     if (!dry_run) {
66228290f37SAlexander Graf         cpu_physical_memory_write(addr, fdt, fdt_size);
663891d51beSBernhard Beschow 
664891d51beSBernhard Beschow         /* Set machine->fdt for 'dumpdtb' QMP/HMP command */
665891d51beSBernhard Beschow         g_free(machine->fdt);
666891d51beSBernhard Beschow         machine->fdt = fdt;
667891d51beSBernhard Beschow     } else {
668891d51beSBernhard Beschow         g_free(fdt);
669cba2026aSAlexander Graf     }
670cba2026aSAlexander Graf     ret = fdt_size;
6717ec632b4Spbrook 
6721db09b84Saurel32 out:
673347dd79dSAlexander Graf     g_free(pci_map);
6741db09b84Saurel32 
67504088adbSLiu Yu     return ret;
6761db09b84Saurel32 }
6771db09b84Saurel32 
67828290f37SAlexander Graf typedef struct DeviceTreeParams {
67903f04809SIgor Mammedov     PPCE500MachineState *machine;
68028290f37SAlexander Graf     hwaddr addr;
68128290f37SAlexander Graf     hwaddr initrd_base;
68228290f37SAlexander Graf     hwaddr initrd_size;
683903585deSAlexander Graf     hwaddr kernel_base;
684903585deSAlexander Graf     hwaddr kernel_size;
685f7087343SAlexander Graf     Notifier notifier;
68628290f37SAlexander Graf } DeviceTreeParams;
68728290f37SAlexander Graf 
ppce500_reset_device_tree(void * opaque)68828290f37SAlexander Graf static void ppce500_reset_device_tree(void *opaque)
68928290f37SAlexander Graf {
69028290f37SAlexander Graf     DeviceTreeParams *p = opaque;
69103f04809SIgor Mammedov     ppce500_load_device_tree(p->machine, p->addr, p->initrd_base,
692903585deSAlexander Graf                              p->initrd_size, p->kernel_base, p->kernel_size,
693903585deSAlexander Graf                              false);
69428290f37SAlexander Graf }
69528290f37SAlexander Graf 
ppce500_init_notify(Notifier * notifier,void * data)696f7087343SAlexander Graf static void ppce500_init_notify(Notifier *notifier, void *data)
697f7087343SAlexander Graf {
698f7087343SAlexander Graf     DeviceTreeParams *p = container_of(notifier, DeviceTreeParams, notifier);
699f7087343SAlexander Graf     ppce500_reset_device_tree(p);
700f7087343SAlexander Graf }
701f7087343SAlexander Graf 
ppce500_prep_device_tree(PPCE500MachineState * machine,hwaddr addr,hwaddr initrd_base,hwaddr initrd_size,hwaddr kernel_base,hwaddr kernel_size)70203f04809SIgor Mammedov static int ppce500_prep_device_tree(PPCE500MachineState *machine,
70328290f37SAlexander Graf                                     hwaddr addr,
70428290f37SAlexander Graf                                     hwaddr initrd_base,
705903585deSAlexander Graf                                     hwaddr initrd_size,
706903585deSAlexander Graf                                     hwaddr kernel_base,
707903585deSAlexander Graf                                     hwaddr kernel_size)
70828290f37SAlexander Graf {
70928290f37SAlexander Graf     DeviceTreeParams *p = g_new(DeviceTreeParams, 1);
7103ef96221SMarcel Apfelbaum     p->machine = machine;
71128290f37SAlexander Graf     p->addr = addr;
71228290f37SAlexander Graf     p->initrd_base = initrd_base;
71328290f37SAlexander Graf     p->initrd_size = initrd_size;
714903585deSAlexander Graf     p->kernel_base = kernel_base;
715903585deSAlexander Graf     p->kernel_size = kernel_size;
71628290f37SAlexander Graf 
7176ec65b69SMaksim Kostin     qemu_register_reset_nosnapshotload(ppce500_reset_device_tree, p);
718f7087343SAlexander Graf     p->notifier.notify = ppce500_init_notify;
719f7087343SAlexander Graf     qemu_add_machine_init_done_notifier(&p->notifier);
72028290f37SAlexander Graf 
72128290f37SAlexander Graf     /* Issue the device tree loader once, so that we get the size of the blob */
72203f04809SIgor Mammedov     return ppce500_load_device_tree(machine, addr, initrd_base, initrd_size,
72303f04809SIgor Mammedov                                     kernel_base, kernel_size, true);
72428290f37SAlexander Graf }
72528290f37SAlexander Graf 
booke206_page_size_to_tlb(uint64_t size)726779a30dfSBALATON Zoltan static hwaddr booke206_page_size_to_tlb(uint64_t size)
727d1e256feSAlexander Graf {
728ab3dd749SPhilippe Mathieu-Daudé     return 63 - clz64(size / KiB);
729d1e256feSAlexander Graf }
730d1e256feSAlexander Graf 
booke206_set_tlb(ppcmas_tlb_t * tlb,target_ulong va,hwaddr pa,hwaddr len)731779a30dfSBALATON Zoltan void booke206_set_tlb(ppcmas_tlb_t *tlb, target_ulong va, hwaddr pa,
732779a30dfSBALATON Zoltan                       hwaddr len)
733779a30dfSBALATON Zoltan {
734779a30dfSBALATON Zoltan     tlb->mas1 = booke206_page_size_to_tlb(len) << MAS1_TSIZE_SHIFT;
735779a30dfSBALATON Zoltan     tlb->mas1 |= MAS1_VALID;
736779a30dfSBALATON Zoltan     tlb->mas2 = va & TARGET_PAGE_MASK;
737779a30dfSBALATON Zoltan     tlb->mas7_3 = pa & TARGET_PAGE_MASK;
738779a30dfSBALATON Zoltan     tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
739779a30dfSBALATON Zoltan }
740779a30dfSBALATON Zoltan 
booke206_initial_map_tsize(CPUPPCState * env)741cefd3cdbSBharat Bhushan static int booke206_initial_map_tsize(CPUPPCState *env)
7423b989d49SAlexander Graf {
743cba2026aSAlexander Graf     struct boot_info *bi = env->load_info;
744cefd3cdbSBharat Bhushan     hwaddr dt_end;
745cba2026aSAlexander Graf     int ps;
7463b989d49SAlexander Graf 
747cba2026aSAlexander Graf     /* Our initial TLB entry needs to cover everything from 0 to
748cba2026aSAlexander Graf        the device tree top */
749cba2026aSAlexander Graf     dt_end = bi->dt_base + bi->dt_size;
750cba2026aSAlexander Graf     ps = booke206_page_size_to_tlb(dt_end) + 1;
751fb37c302SAlexander Graf     if (ps & 1) {
752fb37c302SAlexander Graf         /* e500v2 can only do even TLB size bits */
753fb37c302SAlexander Graf         ps++;
754fb37c302SAlexander Graf     }
755cefd3cdbSBharat Bhushan     return ps;
756cefd3cdbSBharat Bhushan }
757cefd3cdbSBharat Bhushan 
mmubooke_initial_mapsize(CPUPPCState * env)758cefd3cdbSBharat Bhushan static uint64_t mmubooke_initial_mapsize(CPUPPCState *env)
759cefd3cdbSBharat Bhushan {
760cefd3cdbSBharat Bhushan     int tsize;
761cefd3cdbSBharat Bhushan 
762cefd3cdbSBharat Bhushan     tsize = booke206_initial_map_tsize(env);
763cefd3cdbSBharat Bhushan     return (1ULL << 10 << tsize);
764cefd3cdbSBharat Bhushan }
765cefd3cdbSBharat Bhushan 
ppce500_cpu_reset_sec(void * opaque)766b3305981SScott Wood static void ppce500_cpu_reset_sec(void *opaque)
7675c145dacSAlexander Graf {
76838f92da6SAndreas Färber     PowerPCCPU *cpu = opaque;
769259186a7SAndreas Färber     CPUState *cs = CPU(cpu);
7705c145dacSAlexander Graf 
771259186a7SAndreas Färber     cpu_reset(cs);
7725c145dacSAlexander Graf 
77327103424SAndreas Färber     cs->exception_index = EXCP_HLT;
7743b989d49SAlexander Graf }
7753b989d49SAlexander Graf 
ppce500_cpu_reset(void * opaque)776b3305981SScott Wood static void ppce500_cpu_reset(void *opaque)
7773b989d49SAlexander Graf {
77838f92da6SAndreas Färber     PowerPCCPU *cpu = opaque;
779259186a7SAndreas Färber     CPUState *cs = CPU(cpu);
78038f92da6SAndreas Färber     CPUPPCState *env = &cpu->env;
7813b989d49SAlexander Graf     struct boot_info *bi = env->load_info;
782779a30dfSBALATON Zoltan     uint64_t map_size = mmubooke_initial_mapsize(env);
783779a30dfSBALATON Zoltan     ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0);
7843b989d49SAlexander Graf 
785259186a7SAndreas Färber     cpu_reset(cs);
7863b989d49SAlexander Graf 
7873b989d49SAlexander Graf     /* Set initial guest state. */
788259186a7SAndreas Färber     cs->halted = 0;
789ab3dd749SPhilippe Mathieu-Daudé     env->gpr[1] = (16 * MiB) - 8;
7903b989d49SAlexander Graf     env->gpr[3] = bi->dt_base;
791cefd3cdbSBharat Bhushan     env->gpr[4] = 0;
792cefd3cdbSBharat Bhushan     env->gpr[5] = 0;
793cefd3cdbSBharat Bhushan     env->gpr[6] = EPAPR_MAGIC;
794779a30dfSBALATON Zoltan     env->gpr[7] = map_size;
795cefd3cdbSBharat Bhushan     env->gpr[8] = 0;
796cefd3cdbSBharat Bhushan     env->gpr[9] = 0;
7973b989d49SAlexander Graf     env->nip = bi->entry;
798779a30dfSBALATON Zoltan     /* create initial mapping */
799779a30dfSBALATON Zoltan     booke206_set_tlb(tlb, 0, 0, map_size);
800779a30dfSBALATON Zoltan #ifdef CONFIG_KVM
801779a30dfSBALATON Zoltan     env->tlb_dirty = true;
802779a30dfSBALATON Zoltan #endif
8033b989d49SAlexander Graf }
8043b989d49SAlexander Graf 
ppce500_init_mpic_qemu(PPCE500MachineState * pms,IrqLines * irqs)80503f04809SIgor Mammedov static DeviceState *ppce500_init_mpic_qemu(PPCE500MachineState *pms,
8062104d4f5SGreg Kurz                                            IrqLines  *irqs)
80782fc73b6SScott Wood {
80882fc73b6SScott Wood     DeviceState *dev;
80982fc73b6SScott Wood     SysBusDevice *s;
81082fc73b6SScott Wood     int i, j, k;
81103f04809SIgor Mammedov     MachineState *machine = MACHINE(pms);
812fe6b6346SLike Xu     unsigned int smp_cpus = machine->smp.cpus;
81303f04809SIgor Mammedov     const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(pms);
81482fc73b6SScott Wood 
8153e80f690SMarkus Armbruster     dev = qdev_new(TYPE_OPENPIC);
816d2623129SMarkus Armbruster     object_property_add_child(OBJECT(machine), "pic", OBJECT(dev));
81703f04809SIgor Mammedov     qdev_prop_set_uint32(dev, "model", pmc->mpic_version);
818d85937e6SScott Wood     qdev_prop_set_uint32(dev, "nb_cpus", smp_cpus);
819d85937e6SScott Wood 
82082fc73b6SScott Wood     s = SYS_BUS_DEVICE(dev);
8213c6ef471SMarkus Armbruster     sysbus_realize_and_unref(s, &error_fatal);
82282fc73b6SScott Wood 
82382fc73b6SScott Wood     k = 0;
82482fc73b6SScott Wood     for (i = 0; i < smp_cpus; i++) {
82582fc73b6SScott Wood         for (j = 0; j < OPENPIC_OUTPUT_NB; j++) {
8262104d4f5SGreg Kurz             sysbus_connect_irq(s, k++, irqs[i].irq[j]);
82782fc73b6SScott Wood         }
82882fc73b6SScott Wood     }
82982fc73b6SScott Wood 
830d85937e6SScott Wood     return dev;
831d85937e6SScott Wood }
832d85937e6SScott Wood 
ppce500_init_mpic_kvm(const PPCE500MachineClass * pmc,Error ** errp)83303f04809SIgor Mammedov static DeviceState *ppce500_init_mpic_kvm(const PPCE500MachineClass *pmc,
8342a309354SBernhard Beschow                                           Error **errp)
835d85937e6SScott Wood {
83686d9ff28SPhilippe Mathieu-Daudé #ifdef CONFIG_KVM
837d85937e6SScott Wood     DeviceState *dev;
838d85937e6SScott Wood     CPUState *cs;
839d85937e6SScott Wood 
8403e80f690SMarkus Armbruster     dev = qdev_new(TYPE_KVM_OPENPIC);
84103f04809SIgor Mammedov     qdev_prop_set_uint32(dev, "model", pmc->mpic_version);
842d85937e6SScott Wood 
843668f62ecSMarkus Armbruster     if (!sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), errp)) {
844fe656ebdSMarkus Armbruster         object_unparent(OBJECT(dev));
845d85937e6SScott Wood         return NULL;
846d85937e6SScott Wood     }
847d85937e6SScott Wood 
848bdc44640SAndreas Färber     CPU_FOREACH(cs) {
849d85937e6SScott Wood         if (kvm_openpic_connect_vcpu(dev, cs)) {
850d85937e6SScott Wood             fprintf(stderr, "%s: failed to connect vcpu to irqchip\n",
851d85937e6SScott Wood                     __func__);
852d85937e6SScott Wood             abort();
853d85937e6SScott Wood         }
854d85937e6SScott Wood     }
855d85937e6SScott Wood 
856d85937e6SScott Wood     return dev;
85786d9ff28SPhilippe Mathieu-Daudé #else
85886d9ff28SPhilippe Mathieu-Daudé     g_assert_not_reached();
85986d9ff28SPhilippe Mathieu-Daudé #endif
860d85937e6SScott Wood }
861d85937e6SScott Wood 
ppce500_init_mpic(PPCE500MachineState * pms,MemoryRegion * ccsr,IrqLines * irqs)86203f04809SIgor Mammedov static DeviceState *ppce500_init_mpic(PPCE500MachineState *pms,
863c91c187fSMichael Davidsaver                                       MemoryRegion *ccsr,
8642104d4f5SGreg Kurz                                       IrqLines *irqs)
865d85937e6SScott Wood {
86603f04809SIgor Mammedov     const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(pms);
867d85937e6SScott Wood     DeviceState *dev = NULL;
868d85937e6SScott Wood     SysBusDevice *s;
869d85937e6SScott Wood 
870d85937e6SScott Wood     if (kvm_enabled()) {
871fe656ebdSMarkus Armbruster         Error *err = NULL;
872d85937e6SScott Wood 
8734376c40dSPaolo Bonzini         if (kvm_kernel_irqchip_allowed()) {
8742a309354SBernhard Beschow             dev = ppce500_init_mpic_kvm(pmc, &err);
875d85937e6SScott Wood         }
8764376c40dSPaolo Bonzini         if (kvm_kernel_irqchip_required() && !dev) {
877c29b77f9SMarkus Armbruster             error_reportf_err(err,
878c29b77f9SMarkus Armbruster                               "kernel_irqchip requested but unavailable: ");
879fe656ebdSMarkus Armbruster             exit(1);
880d85937e6SScott Wood         }
881d85937e6SScott Wood     }
882d85937e6SScott Wood 
883d85937e6SScott Wood     if (!dev) {
88403f04809SIgor Mammedov         dev = ppce500_init_mpic_qemu(pms, irqs);
885d85937e6SScott Wood     }
886d85937e6SScott Wood 
887d85937e6SScott Wood     s = SYS_BUS_DEVICE(dev);
88882fc73b6SScott Wood     memory_region_add_subregion(ccsr, MPC8544_MPIC_REGS_OFFSET,
88982fc73b6SScott Wood                                 s->mmio[0].memory);
89082fc73b6SScott Wood 
891c91c187fSMichael Davidsaver     return dev;
89282fc73b6SScott Wood }
89382fc73b6SScott Wood 
ppce500_power_off(void * opaque,int line,int on)894016f7758SAlexander Graf static void ppce500_power_off(void *opaque, int line, int on)
895016f7758SAlexander Graf {
896016f7758SAlexander Graf     if (on) {
897cf83f140SEric Blake         qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
898016f7758SAlexander Graf     }
899016f7758SAlexander Graf }
900016f7758SAlexander Graf 
ppce500_init(MachineState * machine)90103f04809SIgor Mammedov void ppce500_init(MachineState *machine)
9021db09b84Saurel32 {
90339186d8aSRichard Henderson     MemoryRegion *address_space_mem = get_system_memory();
90403f04809SIgor Mammedov     PPCE500MachineState *pms = PPCE500_MACHINE(machine);
90503f04809SIgor Mammedov     const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(machine);
906053b7086SThomas Huth     MachineClass *mc = MACHINE_CLASS(pmc);
9071db09b84Saurel32     PCIBus *pci_bus;
908e2684c0bSAndreas Färber     CPUPPCState *env = NULL;
9093812c71fSAlexander Graf     uint64_t loadaddr;
9103812c71fSAlexander Graf     hwaddr kernel_base = -1LL;
9113812c71fSAlexander Graf     int kernel_size = 0;
9123812c71fSAlexander Graf     hwaddr dt_base = 0;
9133812c71fSAlexander Graf     hwaddr initrd_base = 0;
9143812c71fSAlexander Graf     int initrd_size = 0;
9153812c71fSAlexander Graf     hwaddr cur_base = 0;
9163812c71fSAlexander Graf     char *filename;
9178d622594SDavid Engraf     const char *payload_name;
9188d622594SDavid Engraf     bool kernel_as_payload;
9193812c71fSAlexander Graf     hwaddr bios_entry = 0;
9208d622594SDavid Engraf     target_long payload_size;
921a80fc80eSBernhard Beschow     struct boot_info *boot_info = NULL;
9223812c71fSAlexander Graf     int dt_size;
92382fc73b6SScott Wood     int i;
924fe6b6346SLike Xu     unsigned int smp_cpus = machine->smp.cpus;
925d575a6ceSBharat Bhushan     /* irq num for pin INTA, INTB, INTC and INTD is 1, 2, 3 and
926d575a6ceSBharat Bhushan      * 4 respectively */
927d575a6ceSBharat Bhushan     unsigned int pci_irq_nrs[PCI_NUM_PINS] = {1, 2, 3, 4};
9282104d4f5SGreg Kurz     IrqLines *irqs;
929c91c187fSMichael Davidsaver     DeviceState *dev, *mpicdev;
93063e4bf8eSBernhard Beschow     DriveInfo *dinfo;
931e2684c0bSAndreas Färber     CPUPPCState *firstenv = NULL;
9323eddc1beSBharat Bhushan     MemoryRegion *ccsr_addr_space;
933dffb1dc2SBharat Bhushan     SysBusDevice *s;
9343eddc1beSBharat Bhushan     PPCE500CCSRState *ccsr;
9357abb479cSAndrew Randrianasulu     I2CBus *i2c;
9361db09b84Saurel32 
9372104d4f5SGreg Kurz     irqs = g_new0(IrqLines, smp_cpus);
938e61c36d5SAlexander Graf     for (i = 0; i < smp_cpus; i++) {
939397b457dSAndreas Färber         PowerPCCPU *cpu;
94055e5c285SAndreas Färber         CPUState *cs;
941397b457dSAndreas Färber 
942a2c93f06SThiago Jung Bauermann         cpu = POWERPC_CPU(object_new(machine->cpu_type));
943397b457dSAndreas Färber         env = &cpu->env;
94455e5c285SAndreas Färber         cs = CPU(cpu);
9451db09b84Saurel32 
94600469dc3SValentin Plotkin         if (env->mmu_model != POWERPC_MMU_BOOKE206) {
9476f76b817SAlistair Francis             error_report("MMU model %i not supported by this machine",
94800469dc3SValentin Plotkin                          env->mmu_model);
94900469dc3SValentin Plotkin             exit(1);
95000469dc3SValentin Plotkin         }
95100469dc3SValentin Plotkin 
952a2c93f06SThiago Jung Bauermann         /*
953a2c93f06SThiago Jung Bauermann          * Secondary CPU starts in halted state for now. Needs to change
954a2c93f06SThiago Jung Bauermann          * when implementing non-kernel boot.
955a2c93f06SThiago Jung Bauermann          */
956a2c93f06SThiago Jung Bauermann         object_property_set_bool(OBJECT(cs), "start-powered-off", i != 0,
957287fa323SPhilippe Mathieu-Daudé                                  &error_abort);
958a2c93f06SThiago Jung Bauermann         qdev_realize_and_unref(DEVICE(cs), NULL, &error_fatal);
959a2c93f06SThiago Jung Bauermann 
960e61c36d5SAlexander Graf         if (!firstenv) {
961e61c36d5SAlexander Graf             firstenv = env;
962e61c36d5SAlexander Graf         }
963e61c36d5SAlexander Graf 
9645e66cd0cSCédric Le Goater         irqs[i].irq[OPENPIC_OUTPUT_INT] =
9655e66cd0cSCédric Le Goater             qdev_get_gpio_in(DEVICE(cpu), PPCE500_INPUT_INT);
9665e66cd0cSCédric Le Goater         irqs[i].irq[OPENPIC_OUTPUT_CINT] =
9675e66cd0cSCédric Le Goater             qdev_get_gpio_in(DEVICE(cpu), PPCE500_INPUT_CINT);
9686a450df9SAlexander Graf         env->spr_cb[SPR_BOOKE_PIR].default_value = cs->cpu_index = i;
96903f04809SIgor Mammedov         env->mpic_iack = pmc->ccsrbar_base + MPC8544_MPIC_REGS_OFFSET + 0xa0;
970e61c36d5SAlexander Graf 
9710c36ab71SBin Meng         ppc_booke_timers_init(cpu, PLATFORM_CLK_FREQ_HZ, PPC_TIMER_E500);
9723b989d49SAlexander Graf 
9733b989d49SAlexander Graf         /* Register reset handler */
9745c145dacSAlexander Graf         if (!i) {
9755c145dacSAlexander Graf             /* Primary CPU */
976b21e2380SMarkus Armbruster             boot_info = g_new0(struct boot_info, 1);
977b3305981SScott Wood             qemu_register_reset(ppce500_cpu_reset, cpu);
978e61c36d5SAlexander Graf             env->load_info = boot_info;
9795c145dacSAlexander Graf         } else {
9805c145dacSAlexander Graf             /* Secondary CPUs */
981b3305981SScott Wood             qemu_register_reset(ppce500_cpu_reset_sec, cpu);
9825c145dacSAlexander Graf         }
983e61c36d5SAlexander Graf     }
984e61c36d5SAlexander Graf 
985e61c36d5SAlexander Graf     env = firstenv;
9863b989d49SAlexander Graf 
9873538e846SIgor Mammedov     if (!QEMU_IS_ALIGNED(machine->ram_size, RAM_SIZES_ALIGN)) {
9883538e846SIgor Mammedov         error_report("RAM size must be multiple of %" PRIu64, RAM_SIZES_ALIGN);
9893538e846SIgor Mammedov         exit(EXIT_FAILURE);
9903538e846SIgor Mammedov     }
9911db09b84Saurel32 
9921db09b84Saurel32     /* Register Memory */
99397316645SIgor Mammedov     memory_region_add_subregion(address_space_mem, 0, machine->ram);
9941db09b84Saurel32 
9953e80f690SMarkus Armbruster     dev = qdev_new("e500-ccsr");
9961a3e6528SBernhard Beschow     object_property_add_child(OBJECT(machine), "e500-ccsr", OBJECT(dev));
9973c6ef471SMarkus Armbruster     sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
9983eddc1beSBharat Bhushan     ccsr = CCSR(dev);
9993eddc1beSBharat Bhushan     ccsr_addr_space = &ccsr->ccsr_space;
100003f04809SIgor Mammedov     memory_region_add_subregion(address_space_mem, pmc->ccsrbar_base,
10013eddc1beSBharat Bhushan                                 ccsr_addr_space);
1002dffb1dc2SBharat Bhushan 
100303f04809SIgor Mammedov     mpicdev = ppce500_init_mpic(pms, ccsr_addr_space, irqs);
1004ef0efa1aSGan Qixin     g_free(irqs);
10051db09b84Saurel32 
10061db09b84Saurel32     /* Serial */
10079bca0edbSPeter Maydell     if (serial_hd(0)) {
10083eddc1beSBharat Bhushan         serial_mm_init(ccsr_addr_space, MPC8544_SERIAL0_REGS_OFFSET,
1009c91c187fSMichael Davidsaver                        0, qdev_get_gpio_in(mpicdev, 42), 399193,
10109bca0edbSPeter Maydell                        serial_hd(0), DEVICE_BIG_ENDIAN);
10112d48377aSBlue Swirl     }
10121db09b84Saurel32 
10139bca0edbSPeter Maydell     if (serial_hd(1)) {
10143eddc1beSBharat Bhushan         serial_mm_init(ccsr_addr_space, MPC8544_SERIAL1_REGS_OFFSET,
1015c91c187fSMichael Davidsaver                        0, qdev_get_gpio_in(mpicdev, 42), 399193,
10169bca0edbSPeter Maydell                        serial_hd(1), DEVICE_BIG_ENDIAN);
10172d48377aSBlue Swirl     }
10183f288c4bSPhilippe Mathieu-Daudé 
10197abb479cSAndrew Randrianasulu     /* I2C */
10203e80f690SMarkus Armbruster     dev = qdev_new("mpc-i2c");
10217abb479cSAndrew Randrianasulu     s = SYS_BUS_DEVICE(dev);
10223c6ef471SMarkus Armbruster     sysbus_realize_and_unref(s, &error_fatal);
10237abb479cSAndrew Randrianasulu     sysbus_connect_irq(s, 0, qdev_get_gpio_in(mpicdev, MPC8544_I2C_IRQ));
10247abb479cSAndrew Randrianasulu     memory_region_add_subregion(ccsr_addr_space, MPC8544_I2C_REGS_OFFSET,
10257abb479cSAndrew Randrianasulu                                 sysbus_mmio_get_region(s, 0));
1026c620b4eeSBernhard Beschow     i2c = I2C_BUS(qdev_get_child_bus(dev, "i2c"));
10271373b15bSPhilippe Mathieu-Daudé     i2c_slave_create_simple(i2c, "ds1338", RTC_REGS_OFFSET);
10287abb479cSAndrew Randrianasulu 
10293f288c4bSPhilippe Mathieu-Daudé     /* eSDHC */
10303f288c4bSPhilippe Mathieu-Daudé     if (pmc->has_esdhc) {
10314e921beaSBernhard Beschow         dev = qdev_new(TYPE_UNIMPLEMENTED_DEVICE);
10324e921beaSBernhard Beschow         qdev_prop_set_string(dev, "name", "esdhc");
10334e921beaSBernhard Beschow         qdev_prop_set_uint64(dev, "size", MPC85XX_ESDHC_REGS_SIZE);
10344e921beaSBernhard Beschow         s = SYS_BUS_DEVICE(dev);
10354e921beaSBernhard Beschow         sysbus_realize_and_unref(s, &error_fatal);
10364e921beaSBernhard Beschow         memory_region_add_subregion(ccsr_addr_space, MPC85XX_ESDHC_REGS_OFFSET,
10374e921beaSBernhard Beschow                                     sysbus_mmio_get_region(s, 0));
10383f288c4bSPhilippe Mathieu-Daudé 
10393f288c4bSPhilippe Mathieu-Daudé         /*
10403f288c4bSPhilippe Mathieu-Daudé          * Compatible with:
10413f288c4bSPhilippe Mathieu-Daudé          * - SD Host Controller Specification Version 2.0 Part A2
10423f288c4bSPhilippe Mathieu-Daudé          * (See MPC8569E Reference Manual)
10433f288c4bSPhilippe Mathieu-Daudé          */
10443f288c4bSPhilippe Mathieu-Daudé         dev = qdev_new(TYPE_SYSBUS_SDHCI);
10453f288c4bSPhilippe Mathieu-Daudé         qdev_prop_set_uint8(dev, "sd-spec-version", 2);
10463f288c4bSPhilippe Mathieu-Daudé         qdev_prop_set_uint8(dev, "endianness", DEVICE_BIG_ENDIAN);
1047d060b278SBALATON Zoltan         qdev_prop_set_uint8(dev, "vendor", SDHCI_VENDOR_FSL);
10483f288c4bSPhilippe Mathieu-Daudé         s = SYS_BUS_DEVICE(dev);
10493f288c4bSPhilippe Mathieu-Daudé         sysbus_realize_and_unref(s, &error_fatal);
10503f288c4bSPhilippe Mathieu-Daudé         sysbus_connect_irq(s, 0, qdev_get_gpio_in(mpicdev, MPC85XX_ESDHC_IRQ));
10513f288c4bSPhilippe Mathieu-Daudé         memory_region_add_subregion(ccsr_addr_space, MPC85XX_ESDHC_REGS_OFFSET,
10523f288c4bSPhilippe Mathieu-Daudé                                     sysbus_mmio_get_region(s, 0));
10533f288c4bSPhilippe Mathieu-Daudé     }
10541db09b84Saurel32 
1055b0fb8423SAlexander Graf     /* General Utility device */
10563e80f690SMarkus Armbruster     dev = qdev_new("mpc8544-guts");
1057dffb1dc2SBharat Bhushan     s = SYS_BUS_DEVICE(dev);
10583c6ef471SMarkus Armbruster     sysbus_realize_and_unref(s, &error_fatal);
10593eddc1beSBharat Bhushan     memory_region_add_subregion(ccsr_addr_space, MPC8544_UTIL_OFFSET,
1060dffb1dc2SBharat Bhushan                                 sysbus_mmio_get_region(s, 0));
1061b0fb8423SAlexander Graf 
10621db09b84Saurel32     /* PCI */
10633e80f690SMarkus Armbruster     dev = qdev_new("e500-pcihost");
10641a3e6528SBernhard Beschow     object_property_add_child(OBJECT(machine), "pci-host", OBJECT(dev));
106503f04809SIgor Mammedov     qdev_prop_set_uint32(dev, "first_slot", pmc->pci_first_slot);
10663016dca0SBharat Bhushan     qdev_prop_set_uint32(dev, "first_pin_irq", pci_irq_nrs[0]);
1067dffb1dc2SBharat Bhushan     s = SYS_BUS_DEVICE(dev);
10683c6ef471SMarkus Armbruster     sysbus_realize_and_unref(s, &error_fatal);
1069d575a6ceSBharat Bhushan     for (i = 0; i < PCI_NUM_PINS; i++) {
1070c91c187fSMichael Davidsaver         sysbus_connect_irq(s, i, qdev_get_gpio_in(mpicdev, pci_irq_nrs[i]));
1071d575a6ceSBharat Bhushan     }
1072d575a6ceSBharat Bhushan 
10733eddc1beSBharat Bhushan     memory_region_add_subregion(ccsr_addr_space, MPC8544_PCI_REGS_OFFSET,
1074dffb1dc2SBharat Bhushan                                 sysbus_mmio_get_region(s, 0));
1075dffb1dc2SBharat Bhushan 
1076c620b4eeSBernhard Beschow     pci_bus = PCI_BUS(qdev_get_child_bus(dev, "pci.0"));
10771db09b84Saurel32     if (!pci_bus)
10781db09b84Saurel32         printf("couldn't create PCI controller!\n");
10791db09b84Saurel32 
10801db09b84Saurel32     if (pci_bus) {
10811db09b84Saurel32         /* Register network interfaces. */
108236b6968dSDavid Woodhouse         pci_init_nic_devices(pci_bus, mc->default_nic);
10831db09b84Saurel32     }
10841db09b84Saurel32 
10855c145dacSAlexander Graf     /* Register spinning region */
108603f04809SIgor Mammedov     sysbus_create_simple("e500-spin", pmc->spin_base, NULL);
10875c145dacSAlexander Graf 
108803f04809SIgor Mammedov     if (pmc->has_mpc8xxx_gpio) {
1089016f7758SAlexander Graf         qemu_irq poweroff_irq;
1090016f7758SAlexander Graf 
10913e80f690SMarkus Armbruster         dev = qdev_new("mpc8xxx_gpio");
1092b88e77f4SAlexander Graf         s = SYS_BUS_DEVICE(dev);
10933c6ef471SMarkus Armbruster         sysbus_realize_and_unref(s, &error_fatal);
1094c91c187fSMichael Davidsaver         sysbus_connect_irq(s, 0, qdev_get_gpio_in(mpicdev, MPC8XXX_GPIO_IRQ));
1095b88e77f4SAlexander Graf         memory_region_add_subregion(ccsr_addr_space, MPC8XXX_GPIO_OFFSET,
1096b88e77f4SAlexander Graf                                     sysbus_mmio_get_region(s, 0));
1097016f7758SAlexander Graf 
1098016f7758SAlexander Graf         /* Power Off GPIO at Pin 0 */
1099016f7758SAlexander Graf         poweroff_irq = qemu_allocate_irq(ppce500_power_off, NULL, 0);
1100016f7758SAlexander Graf         qdev_connect_gpio_out(dev, 0, poweroff_irq);
1101b88e77f4SAlexander Graf     }
1102b88e77f4SAlexander Graf 
1103f7087343SAlexander Graf     /* Platform Bus Device */
11043e80f690SMarkus Armbruster     dev = qdev_new(TYPE_PLATFORM_BUS_DEVICE);
1105163f3847SKevin Wolf     dev->id = g_strdup(TYPE_PLATFORM_BUS_DEVICE);
110603f04809SIgor Mammedov     qdev_prop_set_uint32(dev, "num_irqs", pmc->platform_bus_num_irqs);
110703f04809SIgor Mammedov     qdev_prop_set_uint32(dev, "mmio_size", pmc->platform_bus_size);
11083c6ef471SMarkus Armbruster     sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
1109a3fc8396SIgor Mammedov     pms->pbus_dev = PLATFORM_BUS_DEVICE(dev);
1110f7087343SAlexander Graf 
1111a3fc8396SIgor Mammedov     s = SYS_BUS_DEVICE(pms->pbus_dev);
111203f04809SIgor Mammedov     for (i = 0; i < pmc->platform_bus_num_irqs; i++) {
111303f04809SIgor Mammedov         int irqn = pmc->platform_bus_first_irq + i;
1114c91c187fSMichael Davidsaver         sysbus_connect_irq(s, i, qdev_get_gpio_in(mpicdev, irqn));
1115f7087343SAlexander Graf     }
1116f7087343SAlexander Graf 
1117f7087343SAlexander Graf     memory_region_add_subregion(address_space_mem,
111803f04809SIgor Mammedov                                 pmc->platform_bus_base,
1119bacb4eb8SBernhard Beschow                                 &pms->pbus_dev->mmio);
1120f7087343SAlexander Graf 
112163e4bf8eSBernhard Beschow     dinfo = drive_get(IF_PFLASH, 0, 0);
112263e4bf8eSBernhard Beschow     if (dinfo) {
112363e4bf8eSBernhard Beschow         BlockBackend *blk = blk_by_legacy_dinfo(dinfo);
112463e4bf8eSBernhard Beschow         BlockDriverState *bs = blk_bs(blk);
112563e4bf8eSBernhard Beschow         uint64_t mmio_size = memory_region_size(&pms->pbus_dev->mmio);
112663e4bf8eSBernhard Beschow         uint64_t size = bdrv_getlength(bs);
112763e4bf8eSBernhard Beschow         uint32_t sector_len = 64 * KiB;
112863e4bf8eSBernhard Beschow 
112963e4bf8eSBernhard Beschow         if (!is_power_of_2(size)) {
113063e4bf8eSBernhard Beschow             error_report("Size of pflash file must be a power of two.");
113163e4bf8eSBernhard Beschow             exit(1);
113263e4bf8eSBernhard Beschow         }
113363e4bf8eSBernhard Beschow 
113463e4bf8eSBernhard Beschow         if (size > mmio_size) {
113563e4bf8eSBernhard Beschow             error_report("Size of pflash file must not be bigger than %" PRIu64
113663e4bf8eSBernhard Beschow                          " bytes.", mmio_size);
113763e4bf8eSBernhard Beschow             exit(1);
113863e4bf8eSBernhard Beschow         }
113963e4bf8eSBernhard Beschow 
114063e4bf8eSBernhard Beschow         if (!QEMU_IS_ALIGNED(size, sector_len)) {
114163e4bf8eSBernhard Beschow             error_report("Size of pflash file must be a multiple of %" PRIu32
114263e4bf8eSBernhard Beschow                          ".", sector_len);
114363e4bf8eSBernhard Beschow             exit(1);
114463e4bf8eSBernhard Beschow         }
114563e4bf8eSBernhard Beschow 
114663e4bf8eSBernhard Beschow         dev = qdev_new(TYPE_PFLASH_CFI01);
114763e4bf8eSBernhard Beschow         qdev_prop_set_drive(dev, "drive", blk);
114863e4bf8eSBernhard Beschow         qdev_prop_set_uint32(dev, "num-blocks", size / sector_len);
114963e4bf8eSBernhard Beschow         qdev_prop_set_uint64(dev, "sector-length", sector_len);
115063e4bf8eSBernhard Beschow         qdev_prop_set_uint8(dev, "width", 2);
115163e4bf8eSBernhard Beschow         qdev_prop_set_bit(dev, "big-endian", true);
115263e4bf8eSBernhard Beschow         qdev_prop_set_uint16(dev, "id0", 0x89);
115363e4bf8eSBernhard Beschow         qdev_prop_set_uint16(dev, "id1", 0x18);
115463e4bf8eSBernhard Beschow         qdev_prop_set_uint16(dev, "id2", 0x0000);
115563e4bf8eSBernhard Beschow         qdev_prop_set_uint16(dev, "id3", 0x0);
115663e4bf8eSBernhard Beschow         qdev_prop_set_string(dev, "name", "e500.flash");
115763e4bf8eSBernhard Beschow         sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
115863e4bf8eSBernhard Beschow 
115963e4bf8eSBernhard Beschow         memory_region_add_subregion(&pms->pbus_dev->mmio, 0,
116063e4bf8eSBernhard Beschow                                     pflash_cfi01_get_memory(PFLASH_CFI01(dev)));
116163e4bf8eSBernhard Beschow     }
116263e4bf8eSBernhard Beschow 
11638d622594SDavid Engraf     /*
11648d622594SDavid Engraf      * Smart firmware defaults ahead!
11658d622594SDavid Engraf      *
11668d622594SDavid Engraf      * We follow the following table to select which payload we execute.
11678d622594SDavid Engraf      *
11688d622594SDavid Engraf      *  -kernel | -bios | payload
11698d622594SDavid Engraf      * ---------+-------+---------
11708d622594SDavid Engraf      *     N    |   Y   | u-boot
11718d622594SDavid Engraf      *     N    |   N   | u-boot
11728d622594SDavid Engraf      *     Y    |   Y   | u-boot
11738d622594SDavid Engraf      *     Y    |   N   | kernel
11748d622594SDavid Engraf      *
11758d622594SDavid Engraf      * This ensures backwards compatibility with how we used to expose
11768d622594SDavid Engraf      * -kernel to users but allows them to run through u-boot as well.
11778d622594SDavid Engraf      */
11788d622594SDavid Engraf     kernel_as_payload = false;
1179cd7b9498SPaolo Bonzini     if (machine->firmware == NULL) {
11803ef96221SMarcel Apfelbaum         if (machine->kernel_filename) {
11818d622594SDavid Engraf             payload_name = machine->kernel_filename;
11828d622594SDavid Engraf             kernel_as_payload = true;
11838d622594SDavid Engraf         } else {
11848d622594SDavid Engraf             payload_name = "u-boot.e500";
11858d622594SDavid Engraf         }
11868d622594SDavid Engraf     } else {
1187cd7b9498SPaolo Bonzini         payload_name = machine->firmware;
11888d622594SDavid Engraf     }
11898d622594SDavid Engraf 
11908d622594SDavid Engraf     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, payload_name);
11913b4f50bdSPeter Maydell     if (!filename) {
11923b4f50bdSPeter Maydell         error_report("could not find firmware/kernel file '%s'", payload_name);
11933b4f50bdSPeter Maydell         exit(1);
11943b4f50bdSPeter Maydell     }
11958d622594SDavid Engraf 
11964366e1dbSLiam Merwick     payload_size = load_elf(filename, NULL, NULL, NULL,
11976cdda0ffSAleksandar Markovic                             &bios_entry, &loadaddr, NULL, NULL,
1198adc1a4a2SPhilippe Mathieu-Daudé                             ELFDATA2MSB, PPC_ELF_MACHINE, 0, 0);
11998d622594SDavid Engraf     if (payload_size < 0) {
12008d622594SDavid Engraf         /*
12018d622594SDavid Engraf          * Hrm. No ELF image? Try a uImage, maybe someone is giving us an
12028d622594SDavid Engraf          * ePAPR compliant kernel
12038d622594SDavid Engraf          */
1204f831f955SNick Hudson         loadaddr = LOAD_UIMAGE_LOADADDR_INVALID;
12058d622594SDavid Engraf         payload_size = load_uimage(filename, &bios_entry, &loadaddr, NULL,
12068d622594SDavid Engraf                                    NULL, NULL);
12078d622594SDavid Engraf         if (payload_size < 0) {
1208371b74e2SMao Zhongyi             error_report("could not load firmware '%s'", filename);
12098d622594SDavid Engraf             exit(1);
12108d622594SDavid Engraf         }
12118d622594SDavid Engraf     }
12128d622594SDavid Engraf 
12138d622594SDavid Engraf     g_free(filename);
12148d622594SDavid Engraf 
12158d622594SDavid Engraf     if (kernel_as_payload) {
12168d622594SDavid Engraf         kernel_base = loadaddr;
12178d622594SDavid Engraf         kernel_size = payload_size;
12188d622594SDavid Engraf     }
12198d622594SDavid Engraf 
12208d622594SDavid Engraf     cur_base = loadaddr + payload_size;
1221ab3dd749SPhilippe Mathieu-Daudé     if (cur_base < 32 * MiB) {
1222b4a5f24aSDavid Engraf         /* u-boot occupies memory up to 32MB, so load blobs above */
1223ab3dd749SPhilippe Mathieu-Daudé         cur_base = 32 * MiB;
1224b4a5f24aSDavid Engraf     }
12258d622594SDavid Engraf 
12268d622594SDavid Engraf     /* Load bare kernel only if no bios/u-boot has been provided */
12278d622594SDavid Engraf     if (machine->kernel_filename && !kernel_as_payload) {
12283812c71fSAlexander Graf         kernel_base = cur_base;
12293812c71fSAlexander Graf         kernel_size = load_image_targphys(machine->kernel_filename,
12303812c71fSAlexander Graf                                           cur_base,
12313538e846SIgor Mammedov                                           machine->ram_size - cur_base);
12321db09b84Saurel32         if (kernel_size < 0) {
12336f76b817SAlistair Francis             error_report("could not load kernel '%s'",
12343ef96221SMarcel Apfelbaum                          machine->kernel_filename);
12351db09b84Saurel32             exit(1);
12361db09b84Saurel32         }
1237528e536eSAlexander Graf 
12383812c71fSAlexander Graf         cur_base += kernel_size;
12391db09b84Saurel32     }
12401db09b84Saurel32 
12411db09b84Saurel32     /* Load initrd. */
12423ef96221SMarcel Apfelbaum     if (machine->initrd_filename) {
1243528e536eSAlexander Graf         initrd_base = (cur_base + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK;
12443ef96221SMarcel Apfelbaum         initrd_size = load_image_targphys(machine->initrd_filename, initrd_base,
12453538e846SIgor Mammedov                                           machine->ram_size - initrd_base);
12461db09b84Saurel32 
12471db09b84Saurel32         if (initrd_size < 0) {
12486f76b817SAlistair Francis             error_report("could not load initial ram disk '%s'",
12493ef96221SMarcel Apfelbaum                          machine->initrd_filename);
12501db09b84Saurel32             exit(1);
12511db09b84Saurel32         }
1252528e536eSAlexander Graf 
1253528e536eSAlexander Graf         cur_base = initrd_base + initrd_size;
12541db09b84Saurel32     }
12551db09b84Saurel32 
12563812c71fSAlexander Graf     /*
12578d622594SDavid Engraf      * Reserve space for dtb behind the kernel image because Linux has a bug
12588d622594SDavid Engraf      * where it can only handle the dtb if it's within the first 64MB of where
12598d622594SDavid Engraf      * <kernel> starts. dtb cannot not reach initrd_base because INITRD_LOAD_PAD
12608d622594SDavid Engraf      * ensures enough space between kernel and initrd.
12613812c71fSAlexander Graf      */
12628d622594SDavid Engraf     dt_base = (loadaddr + payload_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
12633538e846SIgor Mammedov     if (dt_base + DTB_MAX_SIZE > machine->ram_size) {
1264371b74e2SMao Zhongyi             error_report("not enough memory for device tree");
12653812c71fSAlexander Graf             exit(1);
12663812c71fSAlexander Graf     }
12675c145dacSAlexander Graf 
126803f04809SIgor Mammedov     dt_size = ppce500_prep_device_tree(pms, dt_base,
1269903585deSAlexander Graf                                        initrd_base, initrd_size,
12703812c71fSAlexander Graf                                        kernel_base, kernel_size);
1271cba2026aSAlexander Graf     if (dt_size < 0) {
12726f76b817SAlistair Francis         error_report("couldn't load device tree");
12731db09b84Saurel32         exit(1);
12741db09b84Saurel32     }
1275b8dec144SAlexander Graf     assert(dt_size < DTB_MAX_SIZE);
12761db09b84Saurel32 
12773812c71fSAlexander Graf     boot_info->entry = bios_entry;
12783b989d49SAlexander Graf     boot_info->dt_base = dt_base;
1279cba2026aSAlexander Graf     boot_info->dt_size = dt_size;
12801db09b84Saurel32 }
12813eddc1beSBharat Bhushan 
e500_ccsr_initfn(Object * obj)1282d0c2b0d0Sxiaoqiang zhao static void e500_ccsr_initfn(Object *obj)
12833eddc1beSBharat Bhushan {
1284d0c2b0d0Sxiaoqiang zhao     PPCE500CCSRState *ccsr = CCSR(obj);
1285d0c2b0d0Sxiaoqiang zhao     memory_region_init(&ccsr->ccsr_space, obj, "e500-ccsr",
12863eddc1beSBharat Bhushan                        MPC8544_CCSRBAR_SIZE);
12873eddc1beSBharat Bhushan }
12883eddc1beSBharat Bhushan 
12893eddc1beSBharat Bhushan static const TypeInfo e500_ccsr_info = {
12903eddc1beSBharat Bhushan     .name          = TYPE_CCSR,
12913eddc1beSBharat Bhushan     .parent        = TYPE_SYS_BUS_DEVICE,
12923eddc1beSBharat Bhushan     .instance_size = sizeof(PPCE500CCSRState),
1293d0c2b0d0Sxiaoqiang zhao     .instance_init = e500_ccsr_initfn,
12943eddc1beSBharat Bhushan };
12953eddc1beSBharat Bhushan 
129603f04809SIgor Mammedov static const TypeInfo ppce500_info = {
129703f04809SIgor Mammedov     .name          = TYPE_PPCE500_MACHINE,
129803f04809SIgor Mammedov     .parent        = TYPE_MACHINE,
129903f04809SIgor Mammedov     .abstract      = true,
1300a3fc8396SIgor Mammedov     .instance_size = sizeof(PPCE500MachineState),
130103f04809SIgor Mammedov     .class_size    = sizeof(PPCE500MachineClass),
130203f04809SIgor Mammedov };
130303f04809SIgor Mammedov 
e500_register_types(void)13043eddc1beSBharat Bhushan static void e500_register_types(void)
13053eddc1beSBharat Bhushan {
13063eddc1beSBharat Bhushan     type_register_static(&e500_ccsr_info);
130703f04809SIgor Mammedov     type_register_static(&ppce500_info);
13083eddc1beSBharat Bhushan }
13093eddc1beSBharat Bhushan 
13103eddc1beSBharat Bhushan type_init(e500_register_types)
1311