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