xref: /openbmc/qemu/hw/ppc/e500.c (revision 63dc36944383f70f1c7a20f6104966d8560300fa)
14a18e7c9SScott Wood /*
2b3305981SScott Wood  * QEMU PowerPC e500-based platforms
34a18e7c9SScott Wood  *
44a18e7c9SScott Wood  * Copyright (C) 2009 Freescale Semiconductor, Inc. All rights reserved.
54a18e7c9SScott Wood  *
64a18e7c9SScott Wood  * Author: Yu Liu,     <yu.liu@freescale.com>
74a18e7c9SScott Wood  *
84a18e7c9SScott Wood  * This file is derived from hw/ppc440_bamboo.c,
94a18e7c9SScott Wood  * the copyright for that material belongs to the original owners.
104a18e7c9SScott Wood  *
114a18e7c9SScott Wood  * This is free software; you can redistribute it and/or modify
124a18e7c9SScott Wood  * it under the terms of  the GNU General  Public License as published by
134a18e7c9SScott Wood  * the Free Software Foundation;  either version 2 of the  License, or
144a18e7c9SScott Wood  * (at your option) any later version.
154a18e7c9SScott Wood  */
164a18e7c9SScott Wood 
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"
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"
2663e4bf8eSBernhard Beschow #include "hw/block/flash.h"
277e6b5497SBernhard Beschow #include "hw/char/serial-mm.h"
28a2cb15b0SMichael S. Tsirkin #include "hw/pci/pci.h"
2963e4bf8eSBernhard Beschow #include "sysemu/block-backend-io.h"
309c17d615SPaolo Bonzini #include "sysemu/sysemu.h"
319c17d615SPaolo Bonzini #include "sysemu/kvm.h"
3271e8a915SMarkus Armbruster #include "sysemu/reset.h"
3354d31236SMarkus Armbruster #include "sysemu/runstate.h"
344a18e7c9SScott Wood #include "kvm_ppc.h"
359c17d615SPaolo Bonzini #include "sysemu/device_tree.h"
360d09e41aSPaolo Bonzini #include "hw/ppc/openpic.h"
378d085cf0SMark Cave-Ayland #include "hw/ppc/openpic_kvm.h"
380d09e41aSPaolo Bonzini #include "hw/ppc/ppc.h"
39a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
404a18e7c9SScott Wood #include "hw/loader.h"
414a18e7c9SScott Wood #include "elf.h"
424a18e7c9SScott Wood #include "hw/sysbus.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"
513f288c4bSPhilippe Mathieu-Daudé #include "hw/sd/sdhci.h"
523f288c4bSPhilippe Mathieu-Daudé #include "hw/misc/unimp.h"
534a18e7c9SScott Wood 
54cefd3cdbSBharat Bhushan #define EPAPR_MAGIC                (0x45504150)
559dd5eba1SScott Wood #define DTC_LOAD_PAD               0x1800000
564a18e7c9SScott Wood #define DTC_PAD_MASK               0xFFFFF
57ab3dd749SPhilippe Mathieu-Daudé #define DTB_MAX_SIZE               (8 * MiB)
584a18e7c9SScott Wood #define INITRD_LOAD_PAD            0x2000000
594a18e7c9SScott Wood #define INITRD_PAD_MASK            0xFFFFFF
604a18e7c9SScott Wood 
61ab3dd749SPhilippe Mathieu-Daudé #define RAM_SIZES_ALIGN            (64 * MiB)
624a18e7c9SScott Wood 
63b3305981SScott Wood /* TODO: parameterize */
644a18e7c9SScott Wood #define MPC8544_CCSRBAR_SIZE       0x00100000ULL
65dffb1dc2SBharat Bhushan #define MPC8544_MPIC_REGS_OFFSET   0x40000ULL
66a911b7a9SAlexander Graf #define MPC8544_MSI_REGS_OFFSET   0x41600ULL
67dffb1dc2SBharat Bhushan #define MPC8544_SERIAL0_REGS_OFFSET 0x4500ULL
68dffb1dc2SBharat Bhushan #define MPC8544_SERIAL1_REGS_OFFSET 0x4600ULL
69dffb1dc2SBharat Bhushan #define MPC8544_PCI_REGS_OFFSET    0x8000ULL
704a18e7c9SScott Wood #define MPC8544_PCI_REGS_SIZE      0x1000ULL
713f288c4bSPhilippe Mathieu-Daudé #define MPC85XX_ESDHC_REGS_OFFSET  0x2e000ULL
723f288c4bSPhilippe Mathieu-Daudé #define MPC85XX_ESDHC_REGS_SIZE    0x1000ULL
73dffb1dc2SBharat Bhushan #define MPC8544_UTIL_OFFSET        0xe0000ULL
74b88e77f4SAlexander Graf #define MPC8XXX_GPIO_OFFSET        0x000FF000ULL
757abb479cSAndrew Randrianasulu #define MPC8544_I2C_REGS_OFFSET    0x3000ULL
7682e345f5SAmit Tomar #define MPC8XXX_GPIO_IRQ           47
777abb479cSAndrew Randrianasulu #define MPC8544_I2C_IRQ            43
783f288c4bSPhilippe Mathieu-Daudé #define MPC85XX_ESDHC_IRQ          72
797abb479cSAndrew Randrianasulu #define RTC_REGS_OFFSET            0x68
804a18e7c9SScott Wood 
810c36ab71SBin Meng #define PLATFORM_CLK_FREQ_HZ       (400 * 1000 * 1000)
820c36ab71SBin Meng 
834a18e7c9SScott Wood struct boot_info
844a18e7c9SScott Wood {
854a18e7c9SScott Wood     uint32_t dt_base;
864a18e7c9SScott Wood     uint32_t dt_size;
874a18e7c9SScott Wood     uint32_t entry;
884a18e7c9SScott Wood };
894a18e7c9SScott Wood 
pci_map_create(void * fdt,uint32_t mpic,int first_slot,int nr_slots,int * len)90347dd79dSAlexander Graf static uint32_t *pci_map_create(void *fdt, uint32_t mpic, int first_slot,
91347dd79dSAlexander Graf                                 int nr_slots, int *len)
924a18e7c9SScott Wood {
93347dd79dSAlexander Graf     int i = 0;
94347dd79dSAlexander Graf     int slot;
95347dd79dSAlexander Graf     int pci_irq;
969e2c1298SAlexander Graf     int host_irq;
97347dd79dSAlexander Graf     int last_slot = first_slot + nr_slots;
98347dd79dSAlexander Graf     uint32_t *pci_map;
994a18e7c9SScott Wood 
100347dd79dSAlexander Graf     *len = nr_slots * 4 * 7 * sizeof(uint32_t);
101347dd79dSAlexander Graf     pci_map = g_malloc(*len);
102347dd79dSAlexander Graf 
103347dd79dSAlexander Graf     for (slot = first_slot; slot < last_slot; slot++) {
104347dd79dSAlexander Graf         for (pci_irq = 0; pci_irq < 4; pci_irq++) {
105347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(slot << 11);
106347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(0x0);
107347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(0x0);
108347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(pci_irq + 1);
109347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(mpic);
1109e2c1298SAlexander Graf             host_irq = ppce500_pci_map_irq_slot(slot, pci_irq);
1119e2c1298SAlexander Graf             pci_map[i++] = cpu_to_be32(host_irq + 1);
112347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(0x1);
1134a18e7c9SScott Wood         }
1144a18e7c9SScott Wood     }
1154a18e7c9SScott Wood 
116347dd79dSAlexander Graf     assert((i * sizeof(uint32_t)) == *len);
117347dd79dSAlexander Graf 
118347dd79dSAlexander Graf     return pci_map;
119347dd79dSAlexander Graf }
120347dd79dSAlexander Graf 
dt_serial_create(void * fdt,unsigned long long offset,const char * soc,const char * mpic,const char * alias,int idx,bool defcon)1214a18e7c9SScott Wood static void dt_serial_create(void *fdt, unsigned long long offset,
1224a18e7c9SScott Wood                              const char *soc, const char *mpic,
1234a18e7c9SScott Wood                              const char *alias, int idx, bool defcon)
1244a18e7c9SScott Wood {
1252fb513d3SGreg Kurz     char *ser;
1264a18e7c9SScott Wood 
1272fb513d3SGreg Kurz     ser = g_strdup_printf("%s/serial@%llx", soc, offset);
1285a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, ser);
1295a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, ser, "device_type", "serial");
1305a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, ser, "compatible", "ns16550");
1315a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, ser, "reg", offset, 0x100);
1325a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, ser, "cell-index", idx);
13311dbcc70SBin Meng     qemu_fdt_setprop_cell(fdt, ser, "clock-frequency", PLATFORM_CLK_FREQ_HZ);
1345a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, ser, "interrupts", 42, 2);
1355a4348d1SPeter Crosthwaite     qemu_fdt_setprop_phandle(fdt, ser, "interrupt-parent", mpic);
1365a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, "/aliases", alias, ser);
1374a18e7c9SScott Wood 
1384a18e7c9SScott Wood     if (defcon) {
13990ee4e01SNikunj A Dadhania         /*
14090ee4e01SNikunj A Dadhania          * "linux,stdout-path" and "stdout" properties are deprecated by linux
14190ee4e01SNikunj A Dadhania          * kernel. New platforms should only use the "stdout-path" property. Set
14290ee4e01SNikunj A Dadhania          * the new property and continue using older property to remain
14390ee4e01SNikunj A Dadhania          * compatible with the existing firmware.
14490ee4e01SNikunj A Dadhania          */
1455a4348d1SPeter Crosthwaite         qemu_fdt_setprop_string(fdt, "/chosen", "linux,stdout-path", ser);
14690ee4e01SNikunj A Dadhania         qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", ser);
1474a18e7c9SScott Wood     }
1482fb513d3SGreg Kurz     g_free(ser);
1494a18e7c9SScott Wood }
1504a18e7c9SScott Wood 
create_dt_mpc8xxx_gpio(void * fdt,const char * soc,const char * mpic)151b88e77f4SAlexander Graf static void create_dt_mpc8xxx_gpio(void *fdt, const char *soc, const char *mpic)
152b88e77f4SAlexander Graf {
153b88e77f4SAlexander Graf     hwaddr mmio0 = MPC8XXX_GPIO_OFFSET;
154b88e77f4SAlexander Graf     int irq0 = MPC8XXX_GPIO_IRQ;
155b88e77f4SAlexander Graf     gchar *node = g_strdup_printf("%s/gpio@%"PRIx64, soc, mmio0);
156016f7758SAlexander Graf     gchar *poweroff = g_strdup_printf("%s/power-off", soc);
157016f7758SAlexander Graf     int gpio_ph;
158b88e77f4SAlexander Graf 
159b88e77f4SAlexander Graf     qemu_fdt_add_subnode(fdt, node);
160b88e77f4SAlexander Graf     qemu_fdt_setprop_string(fdt, node, "compatible", "fsl,qoriq-gpio");
161b88e77f4SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "reg", mmio0, 0x1000);
162b88e77f4SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "interrupts", irq0, 0x2);
163b88e77f4SAlexander Graf     qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", mpic);
164b88e77f4SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "#gpio-cells", 2);
165b88e77f4SAlexander Graf     qemu_fdt_setprop(fdt, node, "gpio-controller", NULL, 0);
166016f7758SAlexander Graf     gpio_ph = qemu_fdt_alloc_phandle(fdt);
167016f7758SAlexander Graf     qemu_fdt_setprop_cell(fdt, node, "phandle", gpio_ph);
168016f7758SAlexander Graf     qemu_fdt_setprop_cell(fdt, node, "linux,phandle", gpio_ph);
169016f7758SAlexander Graf 
170016f7758SAlexander Graf     /* Power Off Pin */
171016f7758SAlexander Graf     qemu_fdt_add_subnode(fdt, poweroff);
172016f7758SAlexander Graf     qemu_fdt_setprop_string(fdt, poweroff, "compatible", "gpio-poweroff");
173016f7758SAlexander Graf     qemu_fdt_setprop_cells(fdt, poweroff, "gpios", gpio_ph, 0, 0);
174b88e77f4SAlexander Graf 
175b88e77f4SAlexander Graf     g_free(node);
176016f7758SAlexander Graf     g_free(poweroff);
177b88e77f4SAlexander Graf }
178b88e77f4SAlexander Graf 
dt_rtc_create(void * fdt,const char * i2c,const char * alias)1797abb479cSAndrew Randrianasulu static void dt_rtc_create(void *fdt, const char *i2c, const char *alias)
1807abb479cSAndrew Randrianasulu {
1817abb479cSAndrew Randrianasulu     int offset = RTC_REGS_OFFSET;
1827abb479cSAndrew Randrianasulu 
1837abb479cSAndrew Randrianasulu     gchar *rtc = g_strdup_printf("%s/rtc@%"PRIx32, i2c, offset);
1847abb479cSAndrew Randrianasulu     qemu_fdt_add_subnode(fdt, rtc);
1857abb479cSAndrew Randrianasulu     qemu_fdt_setprop_string(fdt, rtc, "compatible", "pericom,pt7c4338");
1867abb479cSAndrew Randrianasulu     qemu_fdt_setprop_cells(fdt, rtc, "reg", offset);
1877abb479cSAndrew Randrianasulu     qemu_fdt_setprop_string(fdt, "/aliases", alias, rtc);
1887abb479cSAndrew Randrianasulu 
1897abb479cSAndrew Randrianasulu     g_free(rtc);
1907abb479cSAndrew Randrianasulu }
1917abb479cSAndrew Randrianasulu 
dt_i2c_create(void * fdt,const char * soc,const char * mpic,const char * alias)1927abb479cSAndrew Randrianasulu static void dt_i2c_create(void *fdt, const char *soc, const char *mpic,
1937abb479cSAndrew Randrianasulu                              const char *alias)
1947abb479cSAndrew Randrianasulu {
1957abb479cSAndrew Randrianasulu     hwaddr mmio0 = MPC8544_I2C_REGS_OFFSET;
1967abb479cSAndrew Randrianasulu     int irq0 = MPC8544_I2C_IRQ;
1977abb479cSAndrew Randrianasulu 
1987abb479cSAndrew Randrianasulu     gchar *i2c = g_strdup_printf("%s/i2c@%"PRIx64, soc, mmio0);
1997abb479cSAndrew Randrianasulu     qemu_fdt_add_subnode(fdt, i2c);
2007abb479cSAndrew Randrianasulu     qemu_fdt_setprop_string(fdt, i2c, "device_type", "i2c");
2017abb479cSAndrew Randrianasulu     qemu_fdt_setprop_string(fdt, i2c, "compatible", "fsl-i2c");
2027abb479cSAndrew Randrianasulu     qemu_fdt_setprop_cells(fdt, i2c, "reg", mmio0, 0x14);
2037abb479cSAndrew Randrianasulu     qemu_fdt_setprop_cells(fdt, i2c, "cell-index", 0);
2047abb479cSAndrew Randrianasulu     qemu_fdt_setprop_cells(fdt, i2c, "interrupts", irq0, 0x2);
2057abb479cSAndrew Randrianasulu     qemu_fdt_setprop_phandle(fdt, i2c, "interrupt-parent", mpic);
206*b5d65592SBernhard Beschow     qemu_fdt_setprop_cell(fdt, i2c, "#size-cells", 0);
207*b5d65592SBernhard Beschow     qemu_fdt_setprop_cell(fdt, i2c, "#address-cells", 1);
2087abb479cSAndrew Randrianasulu     qemu_fdt_setprop_string(fdt, "/aliases", alias, i2c);
2097abb479cSAndrew Randrianasulu 
2107abb479cSAndrew Randrianasulu     g_free(i2c);
2117abb479cSAndrew Randrianasulu }
2127abb479cSAndrew Randrianasulu 
dt_sdhc_create(void * fdt,const char * parent,const char * mpic)2133f288c4bSPhilippe Mathieu-Daudé static void dt_sdhc_create(void *fdt, const char *parent, const char *mpic)
2143f288c4bSPhilippe Mathieu-Daudé {
2153f288c4bSPhilippe Mathieu-Daudé     hwaddr mmio = MPC85XX_ESDHC_REGS_OFFSET;
2163f288c4bSPhilippe Mathieu-Daudé     hwaddr size = MPC85XX_ESDHC_REGS_SIZE;
2173f288c4bSPhilippe Mathieu-Daudé     int irq = MPC85XX_ESDHC_IRQ;
2183f288c4bSPhilippe Mathieu-Daudé     g_autofree char *name = NULL;
2193f288c4bSPhilippe Mathieu-Daudé 
2203f288c4bSPhilippe Mathieu-Daudé     name = g_strdup_printf("%s/sdhc@%" PRIx64, parent, mmio);
2213f288c4bSPhilippe Mathieu-Daudé     qemu_fdt_add_subnode(fdt, name);
2223f288c4bSPhilippe Mathieu-Daudé     qemu_fdt_setprop(fdt, name, "sdhci,auto-cmd12", NULL, 0);
2233f288c4bSPhilippe Mathieu-Daudé     qemu_fdt_setprop_phandle(fdt, name, "interrupt-parent", mpic);
2243f288c4bSPhilippe Mathieu-Daudé     qemu_fdt_setprop_cells(fdt, name, "bus-width", 4);
2253f288c4bSPhilippe Mathieu-Daudé     qemu_fdt_setprop_cells(fdt, name, "interrupts", irq, 0x2);
2263f288c4bSPhilippe Mathieu-Daudé     qemu_fdt_setprop_cells(fdt, name, "reg", mmio, size);
2273f288c4bSPhilippe Mathieu-Daudé     qemu_fdt_setprop_string(fdt, name, "compatible", "fsl,esdhc");
2283f288c4bSPhilippe Mathieu-Daudé }
2297abb479cSAndrew Randrianasulu 
230f7087343SAlexander Graf typedef struct PlatformDevtreeData {
231f7087343SAlexander Graf     void *fdt;
232f7087343SAlexander Graf     const char *mpic;
233f7087343SAlexander Graf     int irq_start;
234f7087343SAlexander Graf     const char *node;
235f7087343SAlexander Graf     PlatformBusDevice *pbus;
236f7087343SAlexander Graf } PlatformDevtreeData;
237f7087343SAlexander Graf 
create_devtree_etsec(SysBusDevice * sbdev,PlatformDevtreeData * data)238fdfb7f2cSAlexander Graf static int create_devtree_etsec(SysBusDevice *sbdev, PlatformDevtreeData *data)
239fdfb7f2cSAlexander Graf {
240fdfb7f2cSAlexander Graf     eTSEC *etsec = ETSEC_COMMON(sbdev);
241fdfb7f2cSAlexander Graf     PlatformBusDevice *pbus = data->pbus;
242fdfb7f2cSAlexander Graf     hwaddr mmio0 = platform_bus_get_mmio_addr(pbus, sbdev, 0);
243fdfb7f2cSAlexander Graf     int irq0 = platform_bus_get_irqn(pbus, sbdev, 0);
244fdfb7f2cSAlexander Graf     int irq1 = platform_bus_get_irqn(pbus, sbdev, 1);
245fdfb7f2cSAlexander Graf     int irq2 = platform_bus_get_irqn(pbus, sbdev, 2);
2464348a3afSBernhard Beschow     gchar *node = g_strdup_printf("%s/ethernet@%"PRIx64, data->node, mmio0);
247fdfb7f2cSAlexander Graf     gchar *group = g_strdup_printf("%s/queue-group", node);
248fdfb7f2cSAlexander Graf     void *fdt = data->fdt;
249fdfb7f2cSAlexander Graf 
250fdfb7f2cSAlexander Graf     assert((int64_t)mmio0 >= 0);
251fdfb7f2cSAlexander Graf     assert(irq0 >= 0);
252fdfb7f2cSAlexander Graf     assert(irq1 >= 0);
253fdfb7f2cSAlexander Graf     assert(irq2 >= 0);
254fdfb7f2cSAlexander Graf 
255fdfb7f2cSAlexander Graf     qemu_fdt_add_subnode(fdt, node);
256e5943b00SBin Meng     qemu_fdt_setprop(fdt, node, "ranges", NULL, 0);
257fdfb7f2cSAlexander Graf     qemu_fdt_setprop_string(fdt, node, "device_type", "network");
258fdfb7f2cSAlexander Graf     qemu_fdt_setprop_string(fdt, node, "compatible", "fsl,etsec2");
259fdfb7f2cSAlexander Graf     qemu_fdt_setprop_string(fdt, node, "model", "eTSEC");
260fdfb7f2cSAlexander Graf     qemu_fdt_setprop(fdt, node, "local-mac-address", etsec->conf.macaddr.a, 6);
261fdfb7f2cSAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "fixed-link", 0, 1, 1000, 0, 0);
26209325678SBin Meng     qemu_fdt_setprop_cells(fdt, node, "#size-cells", 1);
26309325678SBin Meng     qemu_fdt_setprop_cells(fdt, node, "#address-cells", 1);
264fdfb7f2cSAlexander Graf 
265fdfb7f2cSAlexander Graf     qemu_fdt_add_subnode(fdt, group);
266fdfb7f2cSAlexander Graf     qemu_fdt_setprop_cells(fdt, group, "reg", mmio0, 0x1000);
267fdfb7f2cSAlexander Graf     qemu_fdt_setprop_cells(fdt, group, "interrupts",
268fdfb7f2cSAlexander Graf         data->irq_start + irq0, 0x2,
269fdfb7f2cSAlexander Graf         data->irq_start + irq1, 0x2,
270fdfb7f2cSAlexander Graf         data->irq_start + irq2, 0x2);
271fdfb7f2cSAlexander Graf 
272fdfb7f2cSAlexander Graf     g_free(node);
273fdfb7f2cSAlexander Graf     g_free(group);
274fdfb7f2cSAlexander Graf 
275fdfb7f2cSAlexander Graf     return 0;
276fdfb7f2cSAlexander Graf }
277fdfb7f2cSAlexander Graf 
sysbus_device_create_devtree(SysBusDevice * sbdev,void * opaque)2784f01a637SDavid Gibson static void sysbus_device_create_devtree(SysBusDevice *sbdev, void *opaque)
279f7087343SAlexander Graf {
280f7087343SAlexander Graf     PlatformDevtreeData *data = opaque;
281f7087343SAlexander Graf     bool matched = false;
282f7087343SAlexander Graf 
283fdfb7f2cSAlexander Graf     if (object_dynamic_cast(OBJECT(sbdev), TYPE_ETSEC_COMMON)) {
284fdfb7f2cSAlexander Graf         create_devtree_etsec(sbdev, data);
285fdfb7f2cSAlexander Graf         matched = true;
286fdfb7f2cSAlexander Graf     }
287fdfb7f2cSAlexander Graf 
288f7087343SAlexander Graf     if (!matched) {
289f7087343SAlexander Graf         error_report("Device %s is not supported by this machine yet.",
290f7087343SAlexander Graf                      qdev_fw_name(DEVICE(sbdev)));
291f7087343SAlexander Graf         exit(1);
292f7087343SAlexander Graf     }
293f7087343SAlexander Graf }
294f7087343SAlexander Graf 
create_devtree_flash(SysBusDevice * sbdev,PlatformDevtreeData * data)29563e4bf8eSBernhard Beschow static void create_devtree_flash(SysBusDevice *sbdev,
29663e4bf8eSBernhard Beschow                                  PlatformDevtreeData *data)
29763e4bf8eSBernhard Beschow {
29863e4bf8eSBernhard Beschow     g_autofree char *name = NULL;
29963e4bf8eSBernhard Beschow     uint64_t num_blocks = object_property_get_uint(OBJECT(sbdev),
30063e4bf8eSBernhard Beschow                                                    "num-blocks",
30163e4bf8eSBernhard Beschow                                                    &error_fatal);
30263e4bf8eSBernhard Beschow     uint64_t sector_length = object_property_get_uint(OBJECT(sbdev),
30363e4bf8eSBernhard Beschow                                                       "sector-length",
30463e4bf8eSBernhard Beschow                                                       &error_fatal);
30563e4bf8eSBernhard Beschow     uint64_t bank_width = object_property_get_uint(OBJECT(sbdev),
30663e4bf8eSBernhard Beschow                                                    "width",
30763e4bf8eSBernhard Beschow                                                    &error_fatal);
30863e4bf8eSBernhard Beschow     hwaddr flashbase = 0;
30963e4bf8eSBernhard Beschow     hwaddr flashsize = num_blocks * sector_length;
31063e4bf8eSBernhard Beschow     void *fdt = data->fdt;
31163e4bf8eSBernhard Beschow 
31263e4bf8eSBernhard Beschow     name = g_strdup_printf("%s/nor@%" PRIx64, data->node, flashbase);
31363e4bf8eSBernhard Beschow     qemu_fdt_add_subnode(fdt, name);
31463e4bf8eSBernhard Beschow     qemu_fdt_setprop_string(fdt, name, "compatible", "cfi-flash");
31563e4bf8eSBernhard Beschow     qemu_fdt_setprop_sized_cells(fdt, name, "reg",
31663e4bf8eSBernhard Beschow                                  1, flashbase, 1, flashsize);
31763e4bf8eSBernhard Beschow     qemu_fdt_setprop_cell(fdt, name, "bank-width", bank_width);
31863e4bf8eSBernhard Beschow }
31963e4bf8eSBernhard Beschow 
platform_bus_create_devtree(PPCE500MachineState * pms,void * fdt,const char * mpic)320a3fc8396SIgor Mammedov static void platform_bus_create_devtree(PPCE500MachineState *pms,
32103f04809SIgor Mammedov                                         void *fdt, const char *mpic)
322f7087343SAlexander Graf {
323a3fc8396SIgor Mammedov     const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(pms);
32403f04809SIgor Mammedov     gchar *node = g_strdup_printf("/platform@%"PRIx64, pmc->platform_bus_base);
325f7087343SAlexander Graf     const char platcomp[] = "qemu,platform\0simple-bus";
32603f04809SIgor Mammedov     uint64_t addr = pmc->platform_bus_base;
32703f04809SIgor Mammedov     uint64_t size = pmc->platform_bus_size;
32803f04809SIgor Mammedov     int irq_start = pmc->platform_bus_first_irq;
32963e4bf8eSBernhard Beschow     SysBusDevice *sbdev;
33063e4bf8eSBernhard Beschow     bool ambiguous;
331f7087343SAlexander Graf 
332f7087343SAlexander Graf     /* Create a /platform node that we can put all devices into */
333f7087343SAlexander Graf 
334f7087343SAlexander Graf     qemu_fdt_add_subnode(fdt, node);
335f7087343SAlexander Graf     qemu_fdt_setprop(fdt, node, "compatible", platcomp, sizeof(platcomp));
336f7087343SAlexander Graf 
337f7087343SAlexander Graf     /* Our platform bus region is less than 32bit big, so 1 cell is enough for
338f7087343SAlexander Graf        address and size */
339f7087343SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "#size-cells", 1);
340f7087343SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "#address-cells", 1);
341f7087343SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "ranges", 0, addr >> 32, addr, size);
342f7087343SAlexander Graf 
343f7087343SAlexander Graf     qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", mpic);
344f7087343SAlexander Graf 
345a3fc8396SIgor Mammedov     /* Create dt nodes for dynamic devices */
346f7087343SAlexander Graf     PlatformDevtreeData data = {
347f7087343SAlexander Graf         .fdt = fdt,
348f7087343SAlexander Graf         .mpic = mpic,
349f7087343SAlexander Graf         .irq_start = irq_start,
350f7087343SAlexander Graf         .node = node,
351a3fc8396SIgor Mammedov         .pbus = pms->pbus_dev,
352f7087343SAlexander Graf     };
353f7087343SAlexander Graf 
354f7087343SAlexander Graf     /* Loop through all dynamic sysbus devices and create nodes for them */
355f7087343SAlexander Graf     foreach_dynamic_sysbus_device(sysbus_device_create_devtree, &data);
356f7087343SAlexander Graf 
35763e4bf8eSBernhard Beschow     sbdev = SYS_BUS_DEVICE(object_resolve_path_type("", TYPE_PFLASH_CFI01,
35863e4bf8eSBernhard Beschow                                                     &ambiguous));
35963e4bf8eSBernhard Beschow     if (sbdev) {
36063e4bf8eSBernhard Beschow         assert(!ambiguous);
36163e4bf8eSBernhard Beschow         create_devtree_flash(sbdev, &data);
36263e4bf8eSBernhard Beschow     }
36363e4bf8eSBernhard Beschow 
364f7087343SAlexander Graf     g_free(node);
365f7087343SAlexander Graf }
366f7087343SAlexander Graf 
ppce500_load_device_tree(PPCE500MachineState * pms,hwaddr addr,hwaddr initrd_base,hwaddr initrd_size,hwaddr kernel_base,hwaddr kernel_size,bool dry_run)36703f04809SIgor Mammedov static int ppce500_load_device_tree(PPCE500MachineState *pms,
368a8170e5eSAvi Kivity                                     hwaddr addr,
369a8170e5eSAvi Kivity                                     hwaddr initrd_base,
37028290f37SAlexander Graf                                     hwaddr initrd_size,
371903585deSAlexander Graf                                     hwaddr kernel_base,
372903585deSAlexander Graf                                     hwaddr kernel_size,
37328290f37SAlexander Graf                                     bool dry_run)
3744a18e7c9SScott Wood {
37503f04809SIgor Mammedov     MachineState *machine = MACHINE(pms);
376fe6b6346SLike Xu     unsigned int smp_cpus = machine->smp.cpus;
37703f04809SIgor Mammedov     const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(pms);
378b77af26eSRichard Henderson     CPUPPCState *env = cpu_env(first_cpu);
3794a18e7c9SScott Wood     int ret = -1;
3803ef96221SMarcel Apfelbaum     uint64_t mem_reg_property[] = { 0, cpu_to_be64(machine->ram_size) };
3814a18e7c9SScott Wood     int fdt_size;
3824a18e7c9SScott Wood     void *fdt;
3834a18e7c9SScott Wood     uint8_t hypercall[16];
3840c36ab71SBin Meng     uint32_t clock_freq = PLATFORM_CLK_FREQ_HZ;
3850c36ab71SBin Meng     uint32_t tb_freq = PLATFORM_CLK_FREQ_HZ;
3864a18e7c9SScott Wood     int i;
3874a18e7c9SScott Wood     char compatible_sb[] = "fsl,mpc8544-immr\0simple-bus";
3882fb513d3SGreg Kurz     char *soc;
3892fb513d3SGreg Kurz     char *mpic;
3904a18e7c9SScott Wood     uint32_t mpic_ph;
391a911b7a9SAlexander Graf     uint32_t msi_ph;
3922fb513d3SGreg Kurz     char *gutil;
3932fb513d3SGreg Kurz     char *pci;
3942fb513d3SGreg Kurz     char *msi;
395347dd79dSAlexander Graf     uint32_t *pci_map = NULL;
396347dd79dSAlexander Graf     int len;
3974a18e7c9SScott Wood     uint32_t pci_ranges[14] =
3984a18e7c9SScott Wood         {
39903f04809SIgor Mammedov             0x2000000, 0x0, pmc->pci_mmio_bus_base,
40003f04809SIgor Mammedov             pmc->pci_mmio_base >> 32, pmc->pci_mmio_base,
4014a18e7c9SScott Wood             0x0, 0x20000000,
4024a18e7c9SScott Wood 
4034a18e7c9SScott Wood             0x1000000, 0x0, 0x0,
40403f04809SIgor Mammedov             pmc->pci_pio_base >> 32, pmc->pci_pio_base,
4054a18e7c9SScott Wood             0x0, 0x10000,
4064a18e7c9SScott Wood         };
407f2ce39b4SPaolo Bonzini     const char *dtb_file = machine->dtb;
408f2ce39b4SPaolo Bonzini     const char *toplevel_compat = machine->dt_compatible;
409c4b07531SJason A. Donenfeld     uint8_t rng_seed[32];
4104a18e7c9SScott Wood 
4114a18e7c9SScott Wood     if (dtb_file) {
4124a18e7c9SScott Wood         char *filename;
4134a18e7c9SScott Wood         filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_file);
4144a18e7c9SScott Wood         if (!filename) {
4154a18e7c9SScott Wood             goto out;
4164a18e7c9SScott Wood         }
4174a18e7c9SScott Wood 
4184a18e7c9SScott Wood         fdt = load_device_tree(filename, &fdt_size);
4192343dd11SMichael Tokarev         g_free(filename);
4204a18e7c9SScott Wood         if (!fdt) {
4214a18e7c9SScott Wood             goto out;
4224a18e7c9SScott Wood         }
4234a18e7c9SScott Wood         goto done;
4244a18e7c9SScott Wood     }
4254a18e7c9SScott Wood 
4264a18e7c9SScott Wood     fdt = create_device_tree(&fdt_size);
4274a18e7c9SScott Wood     if (fdt == NULL) {
4284a18e7c9SScott Wood         goto out;
4294a18e7c9SScott Wood     }
4304a18e7c9SScott Wood 
4314a18e7c9SScott Wood     /* Manipulate device tree in memory. */
4325a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 2);
4335a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 2);
4344a18e7c9SScott Wood 
4355a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, "/memory");
4365a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, "/memory", "device_type", "memory");
4375a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, "/memory", "reg", mem_reg_property,
4384a18e7c9SScott Wood                      sizeof(mem_reg_property));
4394a18e7c9SScott Wood 
4405a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, "/chosen");
4414a18e7c9SScott Wood     if (initrd_size) {
4425a4348d1SPeter Crosthwaite         ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start",
4434a18e7c9SScott Wood                                     initrd_base);
4444a18e7c9SScott Wood         if (ret < 0) {
4454a18e7c9SScott Wood             fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
4464a18e7c9SScott Wood         }
4474a18e7c9SScott Wood 
4485a4348d1SPeter Crosthwaite         ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
4494a18e7c9SScott Wood                                     (initrd_base + initrd_size));
4504a18e7c9SScott Wood         if (ret < 0) {
4514a18e7c9SScott Wood             fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
4524a18e7c9SScott Wood         }
453903585deSAlexander Graf 
454903585deSAlexander Graf     }
455903585deSAlexander Graf 
456903585deSAlexander Graf     if (kernel_base != -1ULL) {
457903585deSAlexander Graf         qemu_fdt_setprop_cells(fdt, "/chosen", "qemu,boot-kernel",
458903585deSAlexander Graf                                      kernel_base >> 32, kernel_base,
459903585deSAlexander Graf                                      kernel_size >> 32, kernel_size);
4604a18e7c9SScott Wood     }
4614a18e7c9SScott Wood 
4625a4348d1SPeter Crosthwaite     ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
4633ef96221SMarcel Apfelbaum                                       machine->kernel_cmdline);
4644a18e7c9SScott Wood     if (ret < 0)
4654a18e7c9SScott Wood         fprintf(stderr, "couldn't set /chosen/bootargs\n");
4664a18e7c9SScott Wood 
467c4b07531SJason A. Donenfeld     qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed));
468c4b07531SJason A. Donenfeld     qemu_fdt_setprop(fdt, "/chosen", "rng-seed", rng_seed, sizeof(rng_seed));
469c4b07531SJason A. Donenfeld 
4704a18e7c9SScott Wood     if (kvm_enabled()) {
4714a18e7c9SScott Wood         /* Read out host's frequencies */
4724a18e7c9SScott Wood         clock_freq = kvmppc_get_clockfreq();
4734a18e7c9SScott Wood         tb_freq = kvmppc_get_tbfreq();
4744a18e7c9SScott Wood 
4754a18e7c9SScott Wood         /* indicate KVM hypercall interface */
4765a4348d1SPeter Crosthwaite         qemu_fdt_add_subnode(fdt, "/hypervisor");
4775a4348d1SPeter Crosthwaite         qemu_fdt_setprop_string(fdt, "/hypervisor", "compatible",
4784a18e7c9SScott Wood                                 "linux,kvm");
4794a18e7c9SScott Wood         kvmppc_get_hypercall(env, hypercall, sizeof(hypercall));
4805a4348d1SPeter Crosthwaite         qemu_fdt_setprop(fdt, "/hypervisor", "hcall-instructions",
4814a18e7c9SScott Wood                          hypercall, sizeof(hypercall));
4821a61a9aeSStuart Yoder         /* if KVM supports the idle hcall, set property indicating this */
4831a61a9aeSStuart Yoder         if (kvmppc_get_hasidle(env)) {
4845a4348d1SPeter Crosthwaite             qemu_fdt_setprop(fdt, "/hypervisor", "has-idle", NULL, 0);
4851a61a9aeSStuart Yoder         }
4864a18e7c9SScott Wood     }
4874a18e7c9SScott Wood 
4884a18e7c9SScott Wood     /* Create CPU nodes */
4895a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, "/cpus");
4905a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 1);
4915a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0);
4924a18e7c9SScott Wood 
4934a18e7c9SScott Wood     /* We need to generate the cpu nodes in reverse order, so Linux can pick
4944a18e7c9SScott Wood        the first node as boot node and be happy */
4954a18e7c9SScott Wood     for (i = smp_cpus - 1; i >= 0; i--) {
496440c8152SAndreas Färber         CPUState *cpu;
4972fb513d3SGreg Kurz         char *cpu_name;
49803f04809SIgor Mammedov         uint64_t cpu_release_addr = pmc->spin_base + (i * 0x20);
4994a18e7c9SScott Wood 
500440c8152SAndreas Färber         cpu = qemu_get_cpu(i);
50155e5c285SAndreas Färber         if (cpu == NULL) {
5024a18e7c9SScott Wood             continue;
5034a18e7c9SScott Wood         }
504b77af26eSRichard Henderson         env = cpu_env(cpu);
5054a18e7c9SScott Wood 
5062fb513d3SGreg Kurz         cpu_name = g_strdup_printf("/cpus/PowerPC,8544@%x", i);
5075a4348d1SPeter Crosthwaite         qemu_fdt_add_subnode(fdt, cpu_name);
5085a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq);
5095a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq);
5105a4348d1SPeter Crosthwaite         qemu_fdt_setprop_string(fdt, cpu_name, "device_type", "cpu");
5116d536570SSam Bobroff         qemu_fdt_setprop_cell(fdt, cpu_name, "reg", i);
5125a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-line-size",
5134a18e7c9SScott Wood                               env->dcache_line_size);
5145a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-line-size",
5154a18e7c9SScott Wood                               env->icache_line_size);
5165a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-size", 0x8000);
5175a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-size", 0x8000);
5185a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "bus-frequency", 0);
51955e5c285SAndreas Färber         if (cpu->cpu_index) {
5205a4348d1SPeter Crosthwaite             qemu_fdt_setprop_string(fdt, cpu_name, "status", "disabled");
5215a4348d1SPeter Crosthwaite             qemu_fdt_setprop_string(fdt, cpu_name, "enable-method",
5225a4348d1SPeter Crosthwaite                                     "spin-table");
5235a4348d1SPeter Crosthwaite             qemu_fdt_setprop_u64(fdt, cpu_name, "cpu-release-addr",
5244a18e7c9SScott Wood                                  cpu_release_addr);
5254a18e7c9SScott Wood         } else {
5265a4348d1SPeter Crosthwaite             qemu_fdt_setprop_string(fdt, cpu_name, "status", "okay");
5274a18e7c9SScott Wood         }
5282fb513d3SGreg Kurz         g_free(cpu_name);
5294a18e7c9SScott Wood     }
5304a18e7c9SScott Wood 
5315a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, "/aliases");
5324a18e7c9SScott Wood     /* XXX These should go into their respective devices' code */
5332fb513d3SGreg Kurz     soc = g_strdup_printf("/soc@%"PRIx64, pmc->ccsrbar_base);
5345a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, soc);
5355a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, soc, "device_type", "soc");
5365a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, soc, "compatible", compatible_sb,
5374a18e7c9SScott Wood                      sizeof(compatible_sb));
5385a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, soc, "#address-cells", 1);
5395a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, soc, "#size-cells", 1);
5405a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, soc, "ranges", 0x0,
54103f04809SIgor Mammedov                            pmc->ccsrbar_base >> 32, pmc->ccsrbar_base,
5424a18e7c9SScott Wood                            MPC8544_CCSRBAR_SIZE);
5434a18e7c9SScott Wood     /* XXX should contain a reasonable value */
5445a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, soc, "bus-frequency", 0);
5454a18e7c9SScott Wood 
5462fb513d3SGreg Kurz     mpic = g_strdup_printf("%s/pic@%llx", soc, MPC8544_MPIC_REGS_OFFSET);
5475a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, mpic);
5485a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, mpic, "device_type", "open-pic");
5495a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, mpic, "compatible", "fsl,mpic");
5505a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_OFFSET,
551dffb1dc2SBharat Bhushan                            0x40000);
5525a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, mpic, "#address-cells", 0);
5535a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, mpic, "#interrupt-cells", 2);
5545a4348d1SPeter Crosthwaite     mpic_ph = qemu_fdt_alloc_phandle(fdt);
5555a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, mpic, "phandle", mpic_ph);
5565a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, mpic, "linux,phandle", mpic_ph);
5575a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, mpic, "interrupt-controller", NULL, 0);
5584a18e7c9SScott Wood 
5594a18e7c9SScott Wood     /*
5604a18e7c9SScott Wood      * We have to generate ser1 first, because Linux takes the first
5614a18e7c9SScott Wood      * device it finds in the dt as serial output device. And we generate
5624a18e7c9SScott Wood      * devices in reverse order to the dt.
5634a18e7c9SScott Wood      */
5649bca0edbSPeter Maydell     if (serial_hd(1)) {
565dffb1dc2SBharat Bhushan         dt_serial_create(fdt, MPC8544_SERIAL1_REGS_OFFSET,
5664a18e7c9SScott Wood                          soc, mpic, "serial1", 1, false);
56779c0ff2cSAlexander Graf     }
56879c0ff2cSAlexander Graf 
5699bca0edbSPeter Maydell     if (serial_hd(0)) {
570dffb1dc2SBharat Bhushan         dt_serial_create(fdt, MPC8544_SERIAL0_REGS_OFFSET,
5714a18e7c9SScott Wood                          soc, mpic, "serial0", 0, true);
57279c0ff2cSAlexander Graf     }
5734a18e7c9SScott Wood 
5747abb479cSAndrew Randrianasulu     /* i2c */
5757abb479cSAndrew Randrianasulu     dt_i2c_create(fdt, soc, mpic, "i2c");
5767abb479cSAndrew Randrianasulu 
5777abb479cSAndrew Randrianasulu     dt_rtc_create(fdt, "i2c", "rtc");
5787abb479cSAndrew Randrianasulu 
5793f288c4bSPhilippe Mathieu-Daudé     /* sdhc */
5803f288c4bSPhilippe Mathieu-Daudé     if (pmc->has_esdhc) {
5813f288c4bSPhilippe Mathieu-Daudé         dt_sdhc_create(fdt, soc, mpic);
5823f288c4bSPhilippe Mathieu-Daudé     }
5837abb479cSAndrew Randrianasulu 
5842fb513d3SGreg Kurz     gutil = g_strdup_printf("%s/global-utilities@%llx", soc,
585dffb1dc2SBharat Bhushan                             MPC8544_UTIL_OFFSET);
5865a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, gutil);
5875a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, gutil, "compatible", "fsl,mpc8544-guts");
5885a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, gutil, "reg", MPC8544_UTIL_OFFSET, 0x1000);
5895a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, gutil, "fsl,has-rstcr", NULL, 0);
5902fb513d3SGreg Kurz     g_free(gutil);
5914a18e7c9SScott Wood 
5922fb513d3SGreg Kurz     msi = g_strdup_printf("/%s/msi@%llx", soc, MPC8544_MSI_REGS_OFFSET);
5935a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, msi);
5945a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, msi, "compatible", "fsl,mpic-msi");
5955a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, msi, "reg", MPC8544_MSI_REGS_OFFSET, 0x200);
5965a4348d1SPeter Crosthwaite     msi_ph = qemu_fdt_alloc_phandle(fdt);
5975a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, msi, "msi-available-ranges", 0x0, 0x100);
5985a4348d1SPeter Crosthwaite     qemu_fdt_setprop_phandle(fdt, msi, "interrupt-parent", mpic);
5995a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, msi, "interrupts",
600a911b7a9SAlexander Graf         0xe0, 0x0,
601a911b7a9SAlexander Graf         0xe1, 0x0,
602a911b7a9SAlexander Graf         0xe2, 0x0,
603a911b7a9SAlexander Graf         0xe3, 0x0,
604a911b7a9SAlexander Graf         0xe4, 0x0,
605a911b7a9SAlexander Graf         0xe5, 0x0,
606a911b7a9SAlexander Graf         0xe6, 0x0,
607a911b7a9SAlexander Graf         0xe7, 0x0);
6085a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, msi, "phandle", msi_ph);
6095a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, msi, "linux,phandle", msi_ph);
6102fb513d3SGreg Kurz     g_free(msi);
611a911b7a9SAlexander Graf 
6122fb513d3SGreg Kurz     pci = g_strdup_printf("/pci@%llx",
61303f04809SIgor Mammedov                           pmc->ccsrbar_base + MPC8544_PCI_REGS_OFFSET);
6145a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, pci);
6155a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "cell-index", 0);
6165a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, pci, "compatible", "fsl,mpc8540-pci");
6175a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, pci, "device_type", "pci");
6185a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, pci, "interrupt-map-mask", 0xf800, 0x0,
6194a18e7c9SScott Wood                            0x0, 0x7);
6205a4348d1SPeter Crosthwaite     pci_map = pci_map_create(fdt, qemu_fdt_get_phandle(fdt, mpic),
62103f04809SIgor Mammedov                              pmc->pci_first_slot, pmc->pci_nr_slots,
622492ec48dSAlexander Graf                              &len);
6235a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, pci, "interrupt-map", pci_map, len);
6245a4348d1SPeter Crosthwaite     qemu_fdt_setprop_phandle(fdt, pci, "interrupt-parent", mpic);
6255a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, pci, "interrupts", 24, 2);
6265a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, pci, "bus-range", 0, 255);
6274a18e7c9SScott Wood     for (i = 0; i < 14; i++) {
6284a18e7c9SScott Wood         pci_ranges[i] = cpu_to_be32(pci_ranges[i]);
6294a18e7c9SScott Wood     }
6305a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "fsl,msi", msi_ph);
6315a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, pci, "ranges", pci_ranges, sizeof(pci_ranges));
6322eaaac1fSAlexander Graf     qemu_fdt_setprop_cells(fdt, pci, "reg",
63303f04809SIgor Mammedov                            (pmc->ccsrbar_base + MPC8544_PCI_REGS_OFFSET) >> 32,
63403f04809SIgor Mammedov                            (pmc->ccsrbar_base + MPC8544_PCI_REGS_OFFSET),
6352eaaac1fSAlexander Graf                            0, 0x1000);
6365a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "clock-frequency", 66666666);
6375a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "#interrupt-cells", 1);
6385a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "#size-cells", 2);
6395a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "#address-cells", 3);
6405a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, "/aliases", "pci0", pci);
6412fb513d3SGreg Kurz     g_free(pci);
6424a18e7c9SScott Wood 
64303f04809SIgor Mammedov     if (pmc->has_mpc8xxx_gpio) {
644b88e77f4SAlexander Graf         create_dt_mpc8xxx_gpio(fdt, soc, mpic);
645b88e77f4SAlexander Graf     }
6462fb513d3SGreg Kurz     g_free(soc);
647b88e77f4SAlexander Graf 
648a3fc8396SIgor Mammedov     platform_bus_create_devtree(pms, fdt, mpic);
6490998fcb3SBernhard Beschow 
6502fb513d3SGreg Kurz     g_free(mpic);
651f7087343SAlexander Graf 
65203f04809SIgor Mammedov     pmc->fixup_devtree(fdt);
653e6eaabebSScott Wood 
654e6eaabebSScott Wood     if (toplevel_compat) {
6555a4348d1SPeter Crosthwaite         qemu_fdt_setprop(fdt, "/", "compatible", toplevel_compat,
656e6eaabebSScott Wood                          strlen(toplevel_compat) + 1);
657e6eaabebSScott Wood     }
658e6eaabebSScott Wood 
6594a18e7c9SScott Wood done:
66028290f37SAlexander Graf     if (!dry_run) {
6615a4348d1SPeter Crosthwaite         qemu_fdt_dumpdtb(fdt, fdt_size);
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);
6694a18e7c9SScott Wood     }
6704a18e7c9SScott Wood     ret = fdt_size;
6714a18e7c9SScott Wood 
6724a18e7c9SScott Wood out:
673347dd79dSAlexander Graf     g_free(pci_map);
6744a18e7c9SScott Wood 
6754a18e7c9SScott Wood     return ret;
6764a18e7c9SScott Wood }
6774a18e7c9SScott Wood 
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)
7274a18e7c9SScott Wood {
728ab3dd749SPhilippe Mathieu-Daudé     return 63 - clz64(size / KiB);
7294a18e7c9SScott Wood }
7304a18e7c9SScott Wood 
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)
7424a18e7c9SScott Wood {
7434a18e7c9SScott Wood     struct boot_info *bi = env->load_info;
744cefd3cdbSBharat Bhushan     hwaddr dt_end;
7454a18e7c9SScott Wood     int ps;
7464a18e7c9SScott Wood 
7474a18e7c9SScott Wood     /* Our initial TLB entry needs to cover everything from 0 to
7484a18e7c9SScott Wood        the device tree top */
7494a18e7c9SScott Wood     dt_end = bi->dt_base + bi->dt_size;
7504a18e7c9SScott Wood     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)
7674a18e7c9SScott Wood {
7684a18e7c9SScott Wood     PowerPCCPU *cpu = opaque;
769259186a7SAndreas Färber     CPUState *cs = CPU(cpu);
7704a18e7c9SScott Wood 
771259186a7SAndreas Färber     cpu_reset(cs);
7724a18e7c9SScott Wood 
77327103424SAndreas Färber     cs->exception_index = EXCP_HLT;
7744a18e7c9SScott Wood }
7754a18e7c9SScott Wood 
ppce500_cpu_reset(void * opaque)776b3305981SScott Wood static void ppce500_cpu_reset(void *opaque)
7774a18e7c9SScott Wood {
7784a18e7c9SScott Wood     PowerPCCPU *cpu = opaque;
779259186a7SAndreas Färber     CPUState *cs = CPU(cpu);
7804a18e7c9SScott Wood     CPUPPCState *env = &cpu->env;
7814a18e7c9SScott Wood     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);
7844a18e7c9SScott Wood 
785259186a7SAndreas Färber     cpu_reset(cs);
7864a18e7c9SScott Wood 
7874a18e7c9SScott Wood     /* Set initial guest state. */
788259186a7SAndreas Färber     cs->halted = 0;
789ab3dd749SPhilippe Mathieu-Daudé     env->gpr[1] = (16 * MiB) - 8;
7904a18e7c9SScott Wood     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;
7974a18e7c9SScott Wood     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
8034a18e7c9SScott Wood }
8044a18e7c9SScott Wood 
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)
9024a18e7c9SScott Wood {
9034a18e7c9SScott Wood     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);
9074a18e7c9SScott Wood     PCIBus *pci_bus;
9084a18e7c9SScott Wood     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;
9314a18e7c9SScott Wood     CPUPPCState *firstenv = NULL;
9323eddc1beSBharat Bhushan     MemoryRegion *ccsr_addr_space;
933dffb1dc2SBharat Bhushan     SysBusDevice *s;
9343eddc1beSBharat Bhushan     PPCE500CCSRState *ccsr;
9357abb479cSAndrew Randrianasulu     I2CBus *i2c;
9364a18e7c9SScott Wood 
9372104d4f5SGreg Kurz     irqs = g_new0(IrqLines, smp_cpus);
9384a18e7c9SScott Wood     for (i = 0; i < smp_cpus; i++) {
9394a18e7c9SScott Wood         PowerPCCPU *cpu;
94055e5c285SAndreas Färber         CPUState *cs;
9414a18e7c9SScott Wood 
942a2c93f06SThiago Jung Bauermann         cpu = POWERPC_CPU(object_new(machine->cpu_type));
9434a18e7c9SScott Wood         env = &cpu->env;
94455e5c285SAndreas Färber         cs = CPU(cpu);
9454a18e7c9SScott Wood 
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 
9604a18e7c9SScott Wood         if (!firstenv) {
9614a18e7c9SScott Wood             firstenv = env;
9624a18e7c9SScott Wood         }
9634a18e7c9SScott Wood 
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;
9704a18e7c9SScott Wood 
9710c36ab71SBin Meng         ppc_booke_timers_init(cpu, PLATFORM_CLK_FREQ_HZ, PPC_TIMER_E500);
9724a18e7c9SScott Wood 
9734a18e7c9SScott Wood         /* Register reset handler */
9744a18e7c9SScott Wood         if (!i) {
9754a18e7c9SScott Wood             /* Primary CPU */
976b21e2380SMarkus Armbruster             boot_info = g_new0(struct boot_info, 1);
977b3305981SScott Wood             qemu_register_reset(ppce500_cpu_reset, cpu);
9784a18e7c9SScott Wood             env->load_info = boot_info;
9794a18e7c9SScott Wood         } else {
9804a18e7c9SScott Wood             /* Secondary CPUs */
981b3305981SScott Wood             qemu_register_reset(ppce500_cpu_reset_sec, cpu);
9824a18e7c9SScott Wood         }
9834a18e7c9SScott Wood     }
9844a18e7c9SScott Wood 
9854a18e7c9SScott Wood     env = firstenv;
9864a18e7c9SScott Wood 
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     }
9914a18e7c9SScott Wood 
9924a18e7c9SScott Wood     /* Register Memory */
99397316645SIgor Mammedov     memory_region_add_subregion(address_space_mem, 0, machine->ram);
9944a18e7c9SScott Wood 
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);
10054a18e7c9SScott Wood 
10064a18e7c9SScott Wood     /* 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);
10114a18e7c9SScott Wood     }
10124a18e7c9SScott Wood 
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);
10174a18e7c9SScott Wood     }
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);
10473f288c4bSPhilippe Mathieu-Daudé         s = SYS_BUS_DEVICE(dev);
10483f288c4bSPhilippe Mathieu-Daudé         sysbus_realize_and_unref(s, &error_fatal);
10493f288c4bSPhilippe Mathieu-Daudé         sysbus_connect_irq(s, 0, qdev_get_gpio_in(mpicdev, MPC85XX_ESDHC_IRQ));
10503f288c4bSPhilippe Mathieu-Daudé         memory_region_add_subregion(ccsr_addr_space, MPC85XX_ESDHC_REGS_OFFSET,
10513f288c4bSPhilippe Mathieu-Daudé                                     sysbus_mmio_get_region(s, 0));
10523f288c4bSPhilippe Mathieu-Daudé     }
10534a18e7c9SScott Wood 
10544a18e7c9SScott Wood     /* General Utility device */
10553e80f690SMarkus Armbruster     dev = qdev_new("mpc8544-guts");
1056dffb1dc2SBharat Bhushan     s = SYS_BUS_DEVICE(dev);
10573c6ef471SMarkus Armbruster     sysbus_realize_and_unref(s, &error_fatal);
10583eddc1beSBharat Bhushan     memory_region_add_subregion(ccsr_addr_space, MPC8544_UTIL_OFFSET,
1059dffb1dc2SBharat Bhushan                                 sysbus_mmio_get_region(s, 0));
10604a18e7c9SScott Wood 
10614a18e7c9SScott Wood     /* PCI */
10623e80f690SMarkus Armbruster     dev = qdev_new("e500-pcihost");
10631a3e6528SBernhard Beschow     object_property_add_child(OBJECT(machine), "pci-host", OBJECT(dev));
106403f04809SIgor Mammedov     qdev_prop_set_uint32(dev, "first_slot", pmc->pci_first_slot);
10653016dca0SBharat Bhushan     qdev_prop_set_uint32(dev, "first_pin_irq", pci_irq_nrs[0]);
1066dffb1dc2SBharat Bhushan     s = SYS_BUS_DEVICE(dev);
10673c6ef471SMarkus Armbruster     sysbus_realize_and_unref(s, &error_fatal);
1068d575a6ceSBharat Bhushan     for (i = 0; i < PCI_NUM_PINS; i++) {
1069c91c187fSMichael Davidsaver         sysbus_connect_irq(s, i, qdev_get_gpio_in(mpicdev, pci_irq_nrs[i]));
1070d575a6ceSBharat Bhushan     }
1071d575a6ceSBharat Bhushan 
10723eddc1beSBharat Bhushan     memory_region_add_subregion(ccsr_addr_space, MPC8544_PCI_REGS_OFFSET,
1073dffb1dc2SBharat Bhushan                                 sysbus_mmio_get_region(s, 0));
1074dffb1dc2SBharat Bhushan 
1075c620b4eeSBernhard Beschow     pci_bus = PCI_BUS(qdev_get_child_bus(dev, "pci.0"));
10764a18e7c9SScott Wood     if (!pci_bus)
10774a18e7c9SScott Wood         printf("couldn't create PCI controller!\n");
10784a18e7c9SScott Wood 
10794a18e7c9SScott Wood     if (pci_bus) {
10804a18e7c9SScott Wood         /* Register network interfaces. */
108136b6968dSDavid Woodhouse         pci_init_nic_devices(pci_bus, mc->default_nic);
10824a18e7c9SScott Wood     }
10834a18e7c9SScott Wood 
10844a18e7c9SScott Wood     /* Register spinning region */
108503f04809SIgor Mammedov     sysbus_create_simple("e500-spin", pmc->spin_base, NULL);
10864a18e7c9SScott Wood 
108703f04809SIgor Mammedov     if (pmc->has_mpc8xxx_gpio) {
1088016f7758SAlexander Graf         qemu_irq poweroff_irq;
1089016f7758SAlexander Graf 
10903e80f690SMarkus Armbruster         dev = qdev_new("mpc8xxx_gpio");
1091b88e77f4SAlexander Graf         s = SYS_BUS_DEVICE(dev);
10923c6ef471SMarkus Armbruster         sysbus_realize_and_unref(s, &error_fatal);
1093c91c187fSMichael Davidsaver         sysbus_connect_irq(s, 0, qdev_get_gpio_in(mpicdev, MPC8XXX_GPIO_IRQ));
1094b88e77f4SAlexander Graf         memory_region_add_subregion(ccsr_addr_space, MPC8XXX_GPIO_OFFSET,
1095b88e77f4SAlexander Graf                                     sysbus_mmio_get_region(s, 0));
1096016f7758SAlexander Graf 
1097016f7758SAlexander Graf         /* Power Off GPIO at Pin 0 */
1098016f7758SAlexander Graf         poweroff_irq = qemu_allocate_irq(ppce500_power_off, NULL, 0);
1099016f7758SAlexander Graf         qdev_connect_gpio_out(dev, 0, poweroff_irq);
1100b88e77f4SAlexander Graf     }
1101b88e77f4SAlexander Graf 
1102f7087343SAlexander Graf     /* Platform Bus Device */
11033e80f690SMarkus Armbruster     dev = qdev_new(TYPE_PLATFORM_BUS_DEVICE);
1104163f3847SKevin Wolf     dev->id = g_strdup(TYPE_PLATFORM_BUS_DEVICE);
110503f04809SIgor Mammedov     qdev_prop_set_uint32(dev, "num_irqs", pmc->platform_bus_num_irqs);
110603f04809SIgor Mammedov     qdev_prop_set_uint32(dev, "mmio_size", pmc->platform_bus_size);
11073c6ef471SMarkus Armbruster     sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
1108a3fc8396SIgor Mammedov     pms->pbus_dev = PLATFORM_BUS_DEVICE(dev);
1109f7087343SAlexander Graf 
1110a3fc8396SIgor Mammedov     s = SYS_BUS_DEVICE(pms->pbus_dev);
111103f04809SIgor Mammedov     for (i = 0; i < pmc->platform_bus_num_irqs; i++) {
111203f04809SIgor Mammedov         int irqn = pmc->platform_bus_first_irq + i;
1113c91c187fSMichael Davidsaver         sysbus_connect_irq(s, i, qdev_get_gpio_in(mpicdev, irqn));
1114f7087343SAlexander Graf     }
1115f7087343SAlexander Graf 
1116f7087343SAlexander Graf     memory_region_add_subregion(address_space_mem,
111703f04809SIgor Mammedov                                 pmc->platform_bus_base,
1118bacb4eb8SBernhard Beschow                                 &pms->pbus_dev->mmio);
1119f7087343SAlexander Graf 
112063e4bf8eSBernhard Beschow     dinfo = drive_get(IF_PFLASH, 0, 0);
112163e4bf8eSBernhard Beschow     if (dinfo) {
112263e4bf8eSBernhard Beschow         BlockBackend *blk = blk_by_legacy_dinfo(dinfo);
112363e4bf8eSBernhard Beschow         BlockDriverState *bs = blk_bs(blk);
112463e4bf8eSBernhard Beschow         uint64_t mmio_size = memory_region_size(&pms->pbus_dev->mmio);
112563e4bf8eSBernhard Beschow         uint64_t size = bdrv_getlength(bs);
112663e4bf8eSBernhard Beschow         uint32_t sector_len = 64 * KiB;
112763e4bf8eSBernhard Beschow 
112863e4bf8eSBernhard Beschow         if (!is_power_of_2(size)) {
112963e4bf8eSBernhard Beschow             error_report("Size of pflash file must be a power of two.");
113063e4bf8eSBernhard Beschow             exit(1);
113163e4bf8eSBernhard Beschow         }
113263e4bf8eSBernhard Beschow 
113363e4bf8eSBernhard Beschow         if (size > mmio_size) {
113463e4bf8eSBernhard Beschow             error_report("Size of pflash file must not be bigger than %" PRIu64
113563e4bf8eSBernhard Beschow                          " bytes.", mmio_size);
113663e4bf8eSBernhard Beschow             exit(1);
113763e4bf8eSBernhard Beschow         }
113863e4bf8eSBernhard Beschow 
113963e4bf8eSBernhard Beschow         if (!QEMU_IS_ALIGNED(size, sector_len)) {
114063e4bf8eSBernhard Beschow             error_report("Size of pflash file must be a multiple of %" PRIu32
114163e4bf8eSBernhard Beschow                          ".", sector_len);
114263e4bf8eSBernhard Beschow             exit(1);
114363e4bf8eSBernhard Beschow         }
114463e4bf8eSBernhard Beschow 
114563e4bf8eSBernhard Beschow         dev = qdev_new(TYPE_PFLASH_CFI01);
114663e4bf8eSBernhard Beschow         qdev_prop_set_drive(dev, "drive", blk);
114763e4bf8eSBernhard Beschow         qdev_prop_set_uint32(dev, "num-blocks", size / sector_len);
114863e4bf8eSBernhard Beschow         qdev_prop_set_uint64(dev, "sector-length", sector_len);
114963e4bf8eSBernhard Beschow         qdev_prop_set_uint8(dev, "width", 2);
115063e4bf8eSBernhard Beschow         qdev_prop_set_bit(dev, "big-endian", true);
115163e4bf8eSBernhard Beschow         qdev_prop_set_uint16(dev, "id0", 0x89);
115263e4bf8eSBernhard Beschow         qdev_prop_set_uint16(dev, "id1", 0x18);
115363e4bf8eSBernhard Beschow         qdev_prop_set_uint16(dev, "id2", 0x0000);
115463e4bf8eSBernhard Beschow         qdev_prop_set_uint16(dev, "id3", 0x0);
115563e4bf8eSBernhard Beschow         qdev_prop_set_string(dev, "name", "e500.flash");
115663e4bf8eSBernhard Beschow         sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
115763e4bf8eSBernhard Beschow 
115863e4bf8eSBernhard Beschow         memory_region_add_subregion(&pms->pbus_dev->mmio, 0,
115963e4bf8eSBernhard Beschow                                     pflash_cfi01_get_memory(PFLASH_CFI01(dev)));
116063e4bf8eSBernhard Beschow     }
116163e4bf8eSBernhard Beschow 
11628d622594SDavid Engraf     /*
11638d622594SDavid Engraf      * Smart firmware defaults ahead!
11648d622594SDavid Engraf      *
11658d622594SDavid Engraf      * We follow the following table to select which payload we execute.
11668d622594SDavid Engraf      *
11678d622594SDavid Engraf      *  -kernel | -bios | payload
11688d622594SDavid Engraf      * ---------+-------+---------
11698d622594SDavid Engraf      *     N    |   Y   | u-boot
11708d622594SDavid Engraf      *     N    |   N   | u-boot
11718d622594SDavid Engraf      *     Y    |   Y   | u-boot
11728d622594SDavid Engraf      *     Y    |   N   | kernel
11738d622594SDavid Engraf      *
11748d622594SDavid Engraf      * This ensures backwards compatibility with how we used to expose
11758d622594SDavid Engraf      * -kernel to users but allows them to run through u-boot as well.
11768d622594SDavid Engraf      */
11778d622594SDavid Engraf     kernel_as_payload = false;
1178cd7b9498SPaolo Bonzini     if (machine->firmware == NULL) {
11793ef96221SMarcel Apfelbaum         if (machine->kernel_filename) {
11808d622594SDavid Engraf             payload_name = machine->kernel_filename;
11818d622594SDavid Engraf             kernel_as_payload = true;
11828d622594SDavid Engraf         } else {
11838d622594SDavid Engraf             payload_name = "u-boot.e500";
11848d622594SDavid Engraf         }
11858d622594SDavid Engraf     } else {
1186cd7b9498SPaolo Bonzini         payload_name = machine->firmware;
11878d622594SDavid Engraf     }
11888d622594SDavid Engraf 
11898d622594SDavid Engraf     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, payload_name);
11903b4f50bdSPeter Maydell     if (!filename) {
11913b4f50bdSPeter Maydell         error_report("could not find firmware/kernel file '%s'", payload_name);
11923b4f50bdSPeter Maydell         exit(1);
11933b4f50bdSPeter Maydell     }
11948d622594SDavid Engraf 
11954366e1dbSLiam Merwick     payload_size = load_elf(filename, NULL, NULL, NULL,
11966cdda0ffSAleksandar Markovic                             &bios_entry, &loadaddr, NULL, NULL,
11978d622594SDavid Engraf                             1, PPC_ELF_MACHINE, 0, 0);
11988d622594SDavid Engraf     if (payload_size < 0) {
11998d622594SDavid Engraf         /*
12008d622594SDavid Engraf          * Hrm. No ELF image? Try a uImage, maybe someone is giving us an
12018d622594SDavid Engraf          * ePAPR compliant kernel
12028d622594SDavid Engraf          */
1203f831f955SNick Hudson         loadaddr = LOAD_UIMAGE_LOADADDR_INVALID;
12048d622594SDavid Engraf         payload_size = load_uimage(filename, &bios_entry, &loadaddr, NULL,
12058d622594SDavid Engraf                                    NULL, NULL);
12068d622594SDavid Engraf         if (payload_size < 0) {
1207371b74e2SMao Zhongyi             error_report("could not load firmware '%s'", filename);
12088d622594SDavid Engraf             exit(1);
12098d622594SDavid Engraf         }
12108d622594SDavid Engraf     }
12118d622594SDavid Engraf 
12128d622594SDavid Engraf     g_free(filename);
12138d622594SDavid Engraf 
12148d622594SDavid Engraf     if (kernel_as_payload) {
12158d622594SDavid Engraf         kernel_base = loadaddr;
12168d622594SDavid Engraf         kernel_size = payload_size;
12178d622594SDavid Engraf     }
12188d622594SDavid Engraf 
12198d622594SDavid Engraf     cur_base = loadaddr + payload_size;
1220ab3dd749SPhilippe Mathieu-Daudé     if (cur_base < 32 * MiB) {
1221b4a5f24aSDavid Engraf         /* u-boot occupies memory up to 32MB, so load blobs above */
1222ab3dd749SPhilippe Mathieu-Daudé         cur_base = 32 * MiB;
1223b4a5f24aSDavid Engraf     }
12248d622594SDavid Engraf 
12258d622594SDavid Engraf     /* Load bare kernel only if no bios/u-boot has been provided */
12268d622594SDavid Engraf     if (machine->kernel_filename && !kernel_as_payload) {
12273812c71fSAlexander Graf         kernel_base = cur_base;
12283812c71fSAlexander Graf         kernel_size = load_image_targphys(machine->kernel_filename,
12293812c71fSAlexander Graf                                           cur_base,
12303538e846SIgor Mammedov                                           machine->ram_size - cur_base);
12314a18e7c9SScott Wood         if (kernel_size < 0) {
12326f76b817SAlistair Francis             error_report("could not load kernel '%s'",
12333ef96221SMarcel Apfelbaum                          machine->kernel_filename);
12344a18e7c9SScott Wood             exit(1);
12354a18e7c9SScott Wood         }
1236528e536eSAlexander Graf 
12373812c71fSAlexander Graf         cur_base += kernel_size;
12384a18e7c9SScott Wood     }
12394a18e7c9SScott Wood 
12404a18e7c9SScott Wood     /* Load initrd. */
12413ef96221SMarcel Apfelbaum     if (machine->initrd_filename) {
1242528e536eSAlexander Graf         initrd_base = (cur_base + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK;
12433ef96221SMarcel Apfelbaum         initrd_size = load_image_targphys(machine->initrd_filename, initrd_base,
12443538e846SIgor Mammedov                                           machine->ram_size - initrd_base);
12454a18e7c9SScott Wood 
12464a18e7c9SScott Wood         if (initrd_size < 0) {
12476f76b817SAlistair Francis             error_report("could not load initial ram disk '%s'",
12483ef96221SMarcel Apfelbaum                          machine->initrd_filename);
12494a18e7c9SScott Wood             exit(1);
12504a18e7c9SScott Wood         }
1251528e536eSAlexander Graf 
1252528e536eSAlexander Graf         cur_base = initrd_base + initrd_size;
12534a18e7c9SScott Wood     }
12544a18e7c9SScott Wood 
12553812c71fSAlexander Graf     /*
12568d622594SDavid Engraf      * Reserve space for dtb behind the kernel image because Linux has a bug
12578d622594SDavid Engraf      * where it can only handle the dtb if it's within the first 64MB of where
12588d622594SDavid Engraf      * <kernel> starts. dtb cannot not reach initrd_base because INITRD_LOAD_PAD
12598d622594SDavid Engraf      * ensures enough space between kernel and initrd.
12603812c71fSAlexander Graf      */
12618d622594SDavid Engraf     dt_base = (loadaddr + payload_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
12623538e846SIgor Mammedov     if (dt_base + DTB_MAX_SIZE > machine->ram_size) {
1263371b74e2SMao Zhongyi             error_report("not enough memory for device tree");
12643812c71fSAlexander Graf             exit(1);
12653812c71fSAlexander Graf     }
12664a18e7c9SScott Wood 
126703f04809SIgor Mammedov     dt_size = ppce500_prep_device_tree(pms, dt_base,
1268903585deSAlexander Graf                                        initrd_base, initrd_size,
12693812c71fSAlexander Graf                                        kernel_base, kernel_size);
12704a18e7c9SScott Wood     if (dt_size < 0) {
12716f76b817SAlistair Francis         error_report("couldn't load device tree");
12724a18e7c9SScott Wood         exit(1);
12734a18e7c9SScott Wood     }
1274b8dec144SAlexander Graf     assert(dt_size < DTB_MAX_SIZE);
12754a18e7c9SScott Wood 
12763812c71fSAlexander Graf     boot_info->entry = bios_entry;
12774a18e7c9SScott Wood     boot_info->dt_base = dt_base;
12784a18e7c9SScott Wood     boot_info->dt_size = dt_size;
12794a18e7c9SScott Wood }
12803eddc1beSBharat Bhushan 
e500_ccsr_initfn(Object * obj)1281d0c2b0d0Sxiaoqiang zhao static void e500_ccsr_initfn(Object *obj)
12823eddc1beSBharat Bhushan {
1283d0c2b0d0Sxiaoqiang zhao     PPCE500CCSRState *ccsr = CCSR(obj);
1284d0c2b0d0Sxiaoqiang zhao     memory_region_init(&ccsr->ccsr_space, obj, "e500-ccsr",
12853eddc1beSBharat Bhushan                        MPC8544_CCSRBAR_SIZE);
12863eddc1beSBharat Bhushan }
12873eddc1beSBharat Bhushan 
12883eddc1beSBharat Bhushan static const TypeInfo e500_ccsr_info = {
12893eddc1beSBharat Bhushan     .name          = TYPE_CCSR,
12903eddc1beSBharat Bhushan     .parent        = TYPE_SYS_BUS_DEVICE,
12913eddc1beSBharat Bhushan     .instance_size = sizeof(PPCE500CCSRState),
1292d0c2b0d0Sxiaoqiang zhao     .instance_init = e500_ccsr_initfn,
12933eddc1beSBharat Bhushan };
12943eddc1beSBharat Bhushan 
129503f04809SIgor Mammedov static const TypeInfo ppce500_info = {
129603f04809SIgor Mammedov     .name          = TYPE_PPCE500_MACHINE,
129703f04809SIgor Mammedov     .parent        = TYPE_MACHINE,
129803f04809SIgor Mammedov     .abstract      = true,
1299a3fc8396SIgor Mammedov     .instance_size = sizeof(PPCE500MachineState),
130003f04809SIgor Mammedov     .class_size    = sizeof(PPCE500MachineClass),
130103f04809SIgor Mammedov };
130203f04809SIgor Mammedov 
e500_register_types(void)13033eddc1beSBharat Bhushan static void e500_register_types(void)
13043eddc1beSBharat Bhushan {
13053eddc1beSBharat Bhushan     type_register_static(&e500_ccsr_info);
130603f04809SIgor Mammedov     type_register_static(&ppce500_info);
13073eddc1beSBharat Bhushan }
13083eddc1beSBharat Bhushan 
13093eddc1beSBharat Bhushan type_init(e500_register_types)
1310