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"
270d09e41aSPaolo Bonzini #include "hw/char/serial.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);
2067abb479cSAndrew Randrianasulu qemu_fdt_setprop_string(fdt, "/aliases", alias, i2c);
2077abb479cSAndrew Randrianasulu
2087abb479cSAndrew Randrianasulu g_free(i2c);
2097abb479cSAndrew Randrianasulu }
2107abb479cSAndrew Randrianasulu
dt_sdhc_create(void * fdt,const char * parent,const char * mpic)2113f288c4bSPhilippe Mathieu-Daudé static void dt_sdhc_create(void *fdt, const char *parent, const char *mpic)
2123f288c4bSPhilippe Mathieu-Daudé {
2133f288c4bSPhilippe Mathieu-Daudé hwaddr mmio = MPC85XX_ESDHC_REGS_OFFSET;
2143f288c4bSPhilippe Mathieu-Daudé hwaddr size = MPC85XX_ESDHC_REGS_SIZE;
2153f288c4bSPhilippe Mathieu-Daudé int irq = MPC85XX_ESDHC_IRQ;
2163f288c4bSPhilippe Mathieu-Daudé g_autofree char *name = NULL;
2173f288c4bSPhilippe Mathieu-Daudé
2183f288c4bSPhilippe Mathieu-Daudé name = g_strdup_printf("%s/sdhc@%" PRIx64, parent, mmio);
2193f288c4bSPhilippe Mathieu-Daudé qemu_fdt_add_subnode(fdt, name);
2203f288c4bSPhilippe Mathieu-Daudé qemu_fdt_setprop(fdt, name, "sdhci,auto-cmd12", NULL, 0);
2213f288c4bSPhilippe Mathieu-Daudé qemu_fdt_setprop_phandle(fdt, name, "interrupt-parent", mpic);
2223f288c4bSPhilippe Mathieu-Daudé qemu_fdt_setprop_cells(fdt, name, "bus-width", 4);
2233f288c4bSPhilippe Mathieu-Daudé qemu_fdt_setprop_cells(fdt, name, "interrupts", irq, 0x2);
2243f288c4bSPhilippe Mathieu-Daudé qemu_fdt_setprop_cells(fdt, name, "reg", mmio, size);
2253f288c4bSPhilippe Mathieu-Daudé qemu_fdt_setprop_string(fdt, name, "compatible", "fsl,esdhc");
2263f288c4bSPhilippe Mathieu-Daudé }
2277abb479cSAndrew Randrianasulu
228f7087343SAlexander Graf typedef struct PlatformDevtreeData {
229f7087343SAlexander Graf void *fdt;
230f7087343SAlexander Graf const char *mpic;
231f7087343SAlexander Graf int irq_start;
232f7087343SAlexander Graf const char *node;
233f7087343SAlexander Graf PlatformBusDevice *pbus;
234f7087343SAlexander Graf } PlatformDevtreeData;
235f7087343SAlexander Graf
create_devtree_etsec(SysBusDevice * sbdev,PlatformDevtreeData * data)236fdfb7f2cSAlexander Graf static int create_devtree_etsec(SysBusDevice *sbdev, PlatformDevtreeData *data)
237fdfb7f2cSAlexander Graf {
238fdfb7f2cSAlexander Graf eTSEC *etsec = ETSEC_COMMON(sbdev);
239fdfb7f2cSAlexander Graf PlatformBusDevice *pbus = data->pbus;
240fdfb7f2cSAlexander Graf hwaddr mmio0 = platform_bus_get_mmio_addr(pbus, sbdev, 0);
241fdfb7f2cSAlexander Graf int irq0 = platform_bus_get_irqn(pbus, sbdev, 0);
242fdfb7f2cSAlexander Graf int irq1 = platform_bus_get_irqn(pbus, sbdev, 1);
243fdfb7f2cSAlexander Graf int irq2 = platform_bus_get_irqn(pbus, sbdev, 2);
2444348a3afSBernhard Beschow gchar *node = g_strdup_printf("%s/ethernet@%"PRIx64, data->node, mmio0);
245fdfb7f2cSAlexander Graf gchar *group = g_strdup_printf("%s/queue-group", node);
246fdfb7f2cSAlexander Graf void *fdt = data->fdt;
247fdfb7f2cSAlexander Graf
248fdfb7f2cSAlexander Graf assert((int64_t)mmio0 >= 0);
249fdfb7f2cSAlexander Graf assert(irq0 >= 0);
250fdfb7f2cSAlexander Graf assert(irq1 >= 0);
251fdfb7f2cSAlexander Graf assert(irq2 >= 0);
252fdfb7f2cSAlexander Graf
253fdfb7f2cSAlexander Graf qemu_fdt_add_subnode(fdt, node);
254e5943b00SBin Meng qemu_fdt_setprop(fdt, node, "ranges", NULL, 0);
255fdfb7f2cSAlexander Graf qemu_fdt_setprop_string(fdt, node, "device_type", "network");
256fdfb7f2cSAlexander Graf qemu_fdt_setprop_string(fdt, node, "compatible", "fsl,etsec2");
257fdfb7f2cSAlexander Graf qemu_fdt_setprop_string(fdt, node, "model", "eTSEC");
258fdfb7f2cSAlexander Graf qemu_fdt_setprop(fdt, node, "local-mac-address", etsec->conf.macaddr.a, 6);
259fdfb7f2cSAlexander Graf qemu_fdt_setprop_cells(fdt, node, "fixed-link", 0, 1, 1000, 0, 0);
26009325678SBin Meng qemu_fdt_setprop_cells(fdt, node, "#size-cells", 1);
26109325678SBin Meng qemu_fdt_setprop_cells(fdt, node, "#address-cells", 1);
262fdfb7f2cSAlexander Graf
263fdfb7f2cSAlexander Graf qemu_fdt_add_subnode(fdt, group);
264fdfb7f2cSAlexander Graf qemu_fdt_setprop_cells(fdt, group, "reg", mmio0, 0x1000);
265fdfb7f2cSAlexander Graf qemu_fdt_setprop_cells(fdt, group, "interrupts",
266fdfb7f2cSAlexander Graf data->irq_start + irq0, 0x2,
267fdfb7f2cSAlexander Graf data->irq_start + irq1, 0x2,
268fdfb7f2cSAlexander Graf data->irq_start + irq2, 0x2);
269fdfb7f2cSAlexander Graf
270fdfb7f2cSAlexander Graf g_free(node);
271fdfb7f2cSAlexander Graf g_free(group);
272fdfb7f2cSAlexander Graf
273fdfb7f2cSAlexander Graf return 0;
274fdfb7f2cSAlexander Graf }
275fdfb7f2cSAlexander Graf
sysbus_device_create_devtree(SysBusDevice * sbdev,void * opaque)2764f01a637SDavid Gibson static void sysbus_device_create_devtree(SysBusDevice *sbdev, void *opaque)
277f7087343SAlexander Graf {
278f7087343SAlexander Graf PlatformDevtreeData *data = opaque;
279f7087343SAlexander Graf bool matched = false;
280f7087343SAlexander Graf
281fdfb7f2cSAlexander Graf if (object_dynamic_cast(OBJECT(sbdev), TYPE_ETSEC_COMMON)) {
282fdfb7f2cSAlexander Graf create_devtree_etsec(sbdev, data);
283fdfb7f2cSAlexander Graf matched = true;
284fdfb7f2cSAlexander Graf }
285fdfb7f2cSAlexander Graf
286f7087343SAlexander Graf if (!matched) {
287f7087343SAlexander Graf error_report("Device %s is not supported by this machine yet.",
288f7087343SAlexander Graf qdev_fw_name(DEVICE(sbdev)));
289f7087343SAlexander Graf exit(1);
290f7087343SAlexander Graf }
291f7087343SAlexander Graf }
292f7087343SAlexander Graf
create_devtree_flash(SysBusDevice * sbdev,PlatformDevtreeData * data)29363e4bf8eSBernhard Beschow static void create_devtree_flash(SysBusDevice *sbdev,
29463e4bf8eSBernhard Beschow PlatformDevtreeData *data)
29563e4bf8eSBernhard Beschow {
29663e4bf8eSBernhard Beschow g_autofree char *name = NULL;
29763e4bf8eSBernhard Beschow uint64_t num_blocks = object_property_get_uint(OBJECT(sbdev),
29863e4bf8eSBernhard Beschow "num-blocks",
29963e4bf8eSBernhard Beschow &error_fatal);
30063e4bf8eSBernhard Beschow uint64_t sector_length = object_property_get_uint(OBJECT(sbdev),
30163e4bf8eSBernhard Beschow "sector-length",
30263e4bf8eSBernhard Beschow &error_fatal);
30363e4bf8eSBernhard Beschow uint64_t bank_width = object_property_get_uint(OBJECT(sbdev),
30463e4bf8eSBernhard Beschow "width",
30563e4bf8eSBernhard Beschow &error_fatal);
30663e4bf8eSBernhard Beschow hwaddr flashbase = 0;
30763e4bf8eSBernhard Beschow hwaddr flashsize = num_blocks * sector_length;
30863e4bf8eSBernhard Beschow void *fdt = data->fdt;
30963e4bf8eSBernhard Beschow
31063e4bf8eSBernhard Beschow name = g_strdup_printf("%s/nor@%" PRIx64, data->node, flashbase);
31163e4bf8eSBernhard Beschow qemu_fdt_add_subnode(fdt, name);
31263e4bf8eSBernhard Beschow qemu_fdt_setprop_string(fdt, name, "compatible", "cfi-flash");
31363e4bf8eSBernhard Beschow qemu_fdt_setprop_sized_cells(fdt, name, "reg",
31463e4bf8eSBernhard Beschow 1, flashbase, 1, flashsize);
31563e4bf8eSBernhard Beschow qemu_fdt_setprop_cell(fdt, name, "bank-width", bank_width);
31663e4bf8eSBernhard Beschow }
31763e4bf8eSBernhard Beschow
platform_bus_create_devtree(PPCE500MachineState * pms,void * fdt,const char * mpic)318a3fc8396SIgor Mammedov static void platform_bus_create_devtree(PPCE500MachineState *pms,
31903f04809SIgor Mammedov void *fdt, const char *mpic)
320f7087343SAlexander Graf {
321a3fc8396SIgor Mammedov const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(pms);
32203f04809SIgor Mammedov gchar *node = g_strdup_printf("/platform@%"PRIx64, pmc->platform_bus_base);
323f7087343SAlexander Graf const char platcomp[] = "qemu,platform\0simple-bus";
32403f04809SIgor Mammedov uint64_t addr = pmc->platform_bus_base;
32503f04809SIgor Mammedov uint64_t size = pmc->platform_bus_size;
32603f04809SIgor Mammedov int irq_start = pmc->platform_bus_first_irq;
32763e4bf8eSBernhard Beschow SysBusDevice *sbdev;
32863e4bf8eSBernhard Beschow bool ambiguous;
329f7087343SAlexander Graf
330f7087343SAlexander Graf /* Create a /platform node that we can put all devices into */
331f7087343SAlexander Graf
332f7087343SAlexander Graf qemu_fdt_add_subnode(fdt, node);
333f7087343SAlexander Graf qemu_fdt_setprop(fdt, node, "compatible", platcomp, sizeof(platcomp));
334f7087343SAlexander Graf
335f7087343SAlexander Graf /* Our platform bus region is less than 32bit big, so 1 cell is enough for
336f7087343SAlexander Graf address and size */
337f7087343SAlexander Graf qemu_fdt_setprop_cells(fdt, node, "#size-cells", 1);
338f7087343SAlexander Graf qemu_fdt_setprop_cells(fdt, node, "#address-cells", 1);
339f7087343SAlexander Graf qemu_fdt_setprop_cells(fdt, node, "ranges", 0, addr >> 32, addr, size);
340f7087343SAlexander Graf
341f7087343SAlexander Graf qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", mpic);
342f7087343SAlexander Graf
343a3fc8396SIgor Mammedov /* Create dt nodes for dynamic devices */
344f7087343SAlexander Graf PlatformDevtreeData data = {
345f7087343SAlexander Graf .fdt = fdt,
346f7087343SAlexander Graf .mpic = mpic,
347f7087343SAlexander Graf .irq_start = irq_start,
348f7087343SAlexander Graf .node = node,
349a3fc8396SIgor Mammedov .pbus = pms->pbus_dev,
350f7087343SAlexander Graf };
351f7087343SAlexander Graf
352f7087343SAlexander Graf /* Loop through all dynamic sysbus devices and create nodes for them */
353f7087343SAlexander Graf foreach_dynamic_sysbus_device(sysbus_device_create_devtree, &data);
354f7087343SAlexander Graf
35563e4bf8eSBernhard Beschow sbdev = SYS_BUS_DEVICE(object_resolve_path_type("", TYPE_PFLASH_CFI01,
35663e4bf8eSBernhard Beschow &ambiguous));
35763e4bf8eSBernhard Beschow if (sbdev) {
35863e4bf8eSBernhard Beschow assert(!ambiguous);
35963e4bf8eSBernhard Beschow create_devtree_flash(sbdev, &data);
36063e4bf8eSBernhard Beschow }
36163e4bf8eSBernhard Beschow
362f7087343SAlexander Graf g_free(node);
363f7087343SAlexander Graf }
364f7087343SAlexander Graf
ppce500_load_device_tree(PPCE500MachineState * pms,hwaddr addr,hwaddr initrd_base,hwaddr initrd_size,hwaddr kernel_base,hwaddr kernel_size,bool dry_run)36503f04809SIgor Mammedov static int ppce500_load_device_tree(PPCE500MachineState *pms,
366a8170e5eSAvi Kivity hwaddr addr,
367a8170e5eSAvi Kivity hwaddr initrd_base,
36828290f37SAlexander Graf hwaddr initrd_size,
369903585deSAlexander Graf hwaddr kernel_base,
370903585deSAlexander Graf hwaddr kernel_size,
37128290f37SAlexander Graf bool dry_run)
3724a18e7c9SScott Wood {
37303f04809SIgor Mammedov MachineState *machine = MACHINE(pms);
374fe6b6346SLike Xu unsigned int smp_cpus = machine->smp.cpus;
37503f04809SIgor Mammedov const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(pms);
376b77af26eSRichard Henderson CPUPPCState *env = cpu_env(first_cpu);
3774a18e7c9SScott Wood int ret = -1;
3783ef96221SMarcel Apfelbaum uint64_t mem_reg_property[] = { 0, cpu_to_be64(machine->ram_size) };
3794a18e7c9SScott Wood int fdt_size;
3804a18e7c9SScott Wood void *fdt;
3814a18e7c9SScott Wood uint8_t hypercall[16];
3820c36ab71SBin Meng uint32_t clock_freq = PLATFORM_CLK_FREQ_HZ;
3830c36ab71SBin Meng uint32_t tb_freq = PLATFORM_CLK_FREQ_HZ;
3844a18e7c9SScott Wood int i;
3854a18e7c9SScott Wood char compatible_sb[] = "fsl,mpc8544-immr\0simple-bus";
3862fb513d3SGreg Kurz char *soc;
3872fb513d3SGreg Kurz char *mpic;
3884a18e7c9SScott Wood uint32_t mpic_ph;
389a911b7a9SAlexander Graf uint32_t msi_ph;
3902fb513d3SGreg Kurz char *gutil;
3912fb513d3SGreg Kurz char *pci;
3922fb513d3SGreg Kurz char *msi;
393347dd79dSAlexander Graf uint32_t *pci_map = NULL;
394347dd79dSAlexander Graf int len;
3954a18e7c9SScott Wood uint32_t pci_ranges[14] =
3964a18e7c9SScott Wood {
39703f04809SIgor Mammedov 0x2000000, 0x0, pmc->pci_mmio_bus_base,
39803f04809SIgor Mammedov pmc->pci_mmio_base >> 32, pmc->pci_mmio_base,
3994a18e7c9SScott Wood 0x0, 0x20000000,
4004a18e7c9SScott Wood
4014a18e7c9SScott Wood 0x1000000, 0x0, 0x0,
40203f04809SIgor Mammedov pmc->pci_pio_base >> 32, pmc->pci_pio_base,
4034a18e7c9SScott Wood 0x0, 0x10000,
4044a18e7c9SScott Wood };
405f2ce39b4SPaolo Bonzini const char *dtb_file = machine->dtb;
406f2ce39b4SPaolo Bonzini const char *toplevel_compat = machine->dt_compatible;
407c4b07531SJason A. Donenfeld uint8_t rng_seed[32];
4084a18e7c9SScott Wood
4094a18e7c9SScott Wood if (dtb_file) {
4104a18e7c9SScott Wood char *filename;
4114a18e7c9SScott Wood filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_file);
4124a18e7c9SScott Wood if (!filename) {
4134a18e7c9SScott Wood goto out;
4144a18e7c9SScott Wood }
4154a18e7c9SScott Wood
4164a18e7c9SScott Wood fdt = load_device_tree(filename, &fdt_size);
4172343dd11SMichael Tokarev g_free(filename);
4184a18e7c9SScott Wood if (!fdt) {
4194a18e7c9SScott Wood goto out;
4204a18e7c9SScott Wood }
4214a18e7c9SScott Wood goto done;
4224a18e7c9SScott Wood }
4234a18e7c9SScott Wood
4244a18e7c9SScott Wood fdt = create_device_tree(&fdt_size);
4254a18e7c9SScott Wood if (fdt == NULL) {
4264a18e7c9SScott Wood goto out;
4274a18e7c9SScott Wood }
4284a18e7c9SScott Wood
4294a18e7c9SScott Wood /* Manipulate device tree in memory. */
4305a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 2);
4315a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 2);
4324a18e7c9SScott Wood
4335a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, "/memory");
4345a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, "/memory", "device_type", "memory");
4355a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, "/memory", "reg", mem_reg_property,
4364a18e7c9SScott Wood sizeof(mem_reg_property));
4374a18e7c9SScott Wood
4385a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, "/chosen");
4394a18e7c9SScott Wood if (initrd_size) {
4405a4348d1SPeter Crosthwaite ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start",
4414a18e7c9SScott Wood initrd_base);
4424a18e7c9SScott Wood if (ret < 0) {
4434a18e7c9SScott Wood fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
4444a18e7c9SScott Wood }
4454a18e7c9SScott Wood
4465a4348d1SPeter Crosthwaite ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
4474a18e7c9SScott Wood (initrd_base + initrd_size));
4484a18e7c9SScott Wood if (ret < 0) {
4494a18e7c9SScott Wood fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
4504a18e7c9SScott Wood }
451903585deSAlexander Graf
452903585deSAlexander Graf }
453903585deSAlexander Graf
454903585deSAlexander Graf if (kernel_base != -1ULL) {
455903585deSAlexander Graf qemu_fdt_setprop_cells(fdt, "/chosen", "qemu,boot-kernel",
456903585deSAlexander Graf kernel_base >> 32, kernel_base,
457903585deSAlexander Graf kernel_size >> 32, kernel_size);
4584a18e7c9SScott Wood }
4594a18e7c9SScott Wood
4605a4348d1SPeter Crosthwaite ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
4613ef96221SMarcel Apfelbaum machine->kernel_cmdline);
4624a18e7c9SScott Wood if (ret < 0)
4634a18e7c9SScott Wood fprintf(stderr, "couldn't set /chosen/bootargs\n");
4644a18e7c9SScott Wood
465c4b07531SJason A. Donenfeld qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed));
466c4b07531SJason A. Donenfeld qemu_fdt_setprop(fdt, "/chosen", "rng-seed", rng_seed, sizeof(rng_seed));
467c4b07531SJason A. Donenfeld
4684a18e7c9SScott Wood if (kvm_enabled()) {
4694a18e7c9SScott Wood /* Read out host's frequencies */
4704a18e7c9SScott Wood clock_freq = kvmppc_get_clockfreq();
4714a18e7c9SScott Wood tb_freq = kvmppc_get_tbfreq();
4724a18e7c9SScott Wood
4734a18e7c9SScott Wood /* indicate KVM hypercall interface */
4745a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, "/hypervisor");
4755a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, "/hypervisor", "compatible",
4764a18e7c9SScott Wood "linux,kvm");
4774a18e7c9SScott Wood kvmppc_get_hypercall(env, hypercall, sizeof(hypercall));
4785a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, "/hypervisor", "hcall-instructions",
4794a18e7c9SScott Wood hypercall, sizeof(hypercall));
4801a61a9aeSStuart Yoder /* if KVM supports the idle hcall, set property indicating this */
4811a61a9aeSStuart Yoder if (kvmppc_get_hasidle(env)) {
4825a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, "/hypervisor", "has-idle", NULL, 0);
4831a61a9aeSStuart Yoder }
4844a18e7c9SScott Wood }
4854a18e7c9SScott Wood
4864a18e7c9SScott Wood /* Create CPU nodes */
4875a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, "/cpus");
4885a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 1);
4895a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0);
4904a18e7c9SScott Wood
4914a18e7c9SScott Wood /* We need to generate the cpu nodes in reverse order, so Linux can pick
4924a18e7c9SScott Wood the first node as boot node and be happy */
4934a18e7c9SScott Wood for (i = smp_cpus - 1; i >= 0; i--) {
494440c8152SAndreas Färber CPUState *cpu;
4952fb513d3SGreg Kurz char *cpu_name;
49603f04809SIgor Mammedov uint64_t cpu_release_addr = pmc->spin_base + (i * 0x20);
4974a18e7c9SScott Wood
498440c8152SAndreas Färber cpu = qemu_get_cpu(i);
49955e5c285SAndreas Färber if (cpu == NULL) {
5004a18e7c9SScott Wood continue;
5014a18e7c9SScott Wood }
502b77af26eSRichard Henderson env = cpu_env(cpu);
5034a18e7c9SScott Wood
5042fb513d3SGreg Kurz cpu_name = g_strdup_printf("/cpus/PowerPC,8544@%x", i);
5055a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, cpu_name);
5065a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq);
5075a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq);
5085a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, cpu_name, "device_type", "cpu");
5096d536570SSam Bobroff qemu_fdt_setprop_cell(fdt, cpu_name, "reg", i);
5105a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-line-size",
5114a18e7c9SScott Wood env->dcache_line_size);
5125a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-line-size",
5134a18e7c9SScott Wood env->icache_line_size);
5145a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-size", 0x8000);
5155a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-size", 0x8000);
5165a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, cpu_name, "bus-frequency", 0);
51755e5c285SAndreas Färber if (cpu->cpu_index) {
5185a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, cpu_name, "status", "disabled");
5195a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, cpu_name, "enable-method",
5205a4348d1SPeter Crosthwaite "spin-table");
5215a4348d1SPeter Crosthwaite qemu_fdt_setprop_u64(fdt, cpu_name, "cpu-release-addr",
5224a18e7c9SScott Wood cpu_release_addr);
5234a18e7c9SScott Wood } else {
5245a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, cpu_name, "status", "okay");
5254a18e7c9SScott Wood }
5262fb513d3SGreg Kurz g_free(cpu_name);
5274a18e7c9SScott Wood }
5284a18e7c9SScott Wood
5295a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, "/aliases");
5304a18e7c9SScott Wood /* XXX These should go into their respective devices' code */
5312fb513d3SGreg Kurz soc = g_strdup_printf("/soc@%"PRIx64, pmc->ccsrbar_base);
5325a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, soc);
5335a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, soc, "device_type", "soc");
5345a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, soc, "compatible", compatible_sb,
5354a18e7c9SScott Wood sizeof(compatible_sb));
5365a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, soc, "#address-cells", 1);
5375a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, soc, "#size-cells", 1);
5385a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, soc, "ranges", 0x0,
53903f04809SIgor Mammedov pmc->ccsrbar_base >> 32, pmc->ccsrbar_base,
5404a18e7c9SScott Wood MPC8544_CCSRBAR_SIZE);
5414a18e7c9SScott Wood /* XXX should contain a reasonable value */
5425a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, soc, "bus-frequency", 0);
5434a18e7c9SScott Wood
5442fb513d3SGreg Kurz mpic = g_strdup_printf("%s/pic@%llx", soc, MPC8544_MPIC_REGS_OFFSET);
5455a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, mpic);
5465a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, mpic, "device_type", "open-pic");
5475a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, mpic, "compatible", "fsl,mpic");
5485a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_OFFSET,
549dffb1dc2SBharat Bhushan 0x40000);
5505a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, mpic, "#address-cells", 0);
5515a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, mpic, "#interrupt-cells", 2);
5525a4348d1SPeter Crosthwaite mpic_ph = qemu_fdt_alloc_phandle(fdt);
5535a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, mpic, "phandle", mpic_ph);
5545a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, mpic, "linux,phandle", mpic_ph);
5555a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, mpic, "interrupt-controller", NULL, 0);
5564a18e7c9SScott Wood
5574a18e7c9SScott Wood /*
5584a18e7c9SScott Wood * We have to generate ser1 first, because Linux takes the first
5594a18e7c9SScott Wood * device it finds in the dt as serial output device. And we generate
5604a18e7c9SScott Wood * devices in reverse order to the dt.
5614a18e7c9SScott Wood */
5629bca0edbSPeter Maydell if (serial_hd(1)) {
563dffb1dc2SBharat Bhushan dt_serial_create(fdt, MPC8544_SERIAL1_REGS_OFFSET,
5644a18e7c9SScott Wood soc, mpic, "serial1", 1, false);
56579c0ff2cSAlexander Graf }
56679c0ff2cSAlexander Graf
5679bca0edbSPeter Maydell if (serial_hd(0)) {
568dffb1dc2SBharat Bhushan dt_serial_create(fdt, MPC8544_SERIAL0_REGS_OFFSET,
5694a18e7c9SScott Wood soc, mpic, "serial0", 0, true);
57079c0ff2cSAlexander Graf }
5714a18e7c9SScott Wood
5727abb479cSAndrew Randrianasulu /* i2c */
5737abb479cSAndrew Randrianasulu dt_i2c_create(fdt, soc, mpic, "i2c");
5747abb479cSAndrew Randrianasulu
5757abb479cSAndrew Randrianasulu dt_rtc_create(fdt, "i2c", "rtc");
5767abb479cSAndrew Randrianasulu
5773f288c4bSPhilippe Mathieu-Daudé /* sdhc */
5783f288c4bSPhilippe Mathieu-Daudé if (pmc->has_esdhc) {
5793f288c4bSPhilippe Mathieu-Daudé dt_sdhc_create(fdt, soc, mpic);
5803f288c4bSPhilippe Mathieu-Daudé }
5817abb479cSAndrew Randrianasulu
5822fb513d3SGreg Kurz gutil = g_strdup_printf("%s/global-utilities@%llx", soc,
583dffb1dc2SBharat Bhushan MPC8544_UTIL_OFFSET);
5845a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, gutil);
5855a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, gutil, "compatible", "fsl,mpc8544-guts");
5865a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, gutil, "reg", MPC8544_UTIL_OFFSET, 0x1000);
5875a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, gutil, "fsl,has-rstcr", NULL, 0);
5882fb513d3SGreg Kurz g_free(gutil);
5894a18e7c9SScott Wood
5902fb513d3SGreg Kurz msi = g_strdup_printf("/%s/msi@%llx", soc, MPC8544_MSI_REGS_OFFSET);
5915a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, msi);
5925a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, msi, "compatible", "fsl,mpic-msi");
5935a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, msi, "reg", MPC8544_MSI_REGS_OFFSET, 0x200);
5945a4348d1SPeter Crosthwaite msi_ph = qemu_fdt_alloc_phandle(fdt);
5955a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, msi, "msi-available-ranges", 0x0, 0x100);
5965a4348d1SPeter Crosthwaite qemu_fdt_setprop_phandle(fdt, msi, "interrupt-parent", mpic);
5975a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, msi, "interrupts",
598a911b7a9SAlexander Graf 0xe0, 0x0,
599a911b7a9SAlexander Graf 0xe1, 0x0,
600a911b7a9SAlexander Graf 0xe2, 0x0,
601a911b7a9SAlexander Graf 0xe3, 0x0,
602a911b7a9SAlexander Graf 0xe4, 0x0,
603a911b7a9SAlexander Graf 0xe5, 0x0,
604a911b7a9SAlexander Graf 0xe6, 0x0,
605a911b7a9SAlexander Graf 0xe7, 0x0);
6065a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, msi, "phandle", msi_ph);
6075a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, msi, "linux,phandle", msi_ph);
6082fb513d3SGreg Kurz g_free(msi);
609a911b7a9SAlexander Graf
6102fb513d3SGreg Kurz pci = g_strdup_printf("/pci@%llx",
61103f04809SIgor Mammedov pmc->ccsrbar_base + MPC8544_PCI_REGS_OFFSET);
6125a4348d1SPeter Crosthwaite qemu_fdt_add_subnode(fdt, pci);
6135a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, pci, "cell-index", 0);
6145a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, pci, "compatible", "fsl,mpc8540-pci");
6155a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, pci, "device_type", "pci");
6165a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, pci, "interrupt-map-mask", 0xf800, 0x0,
6174a18e7c9SScott Wood 0x0, 0x7);
6185a4348d1SPeter Crosthwaite pci_map = pci_map_create(fdt, qemu_fdt_get_phandle(fdt, mpic),
61903f04809SIgor Mammedov pmc->pci_first_slot, pmc->pci_nr_slots,
620492ec48dSAlexander Graf &len);
6215a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, pci, "interrupt-map", pci_map, len);
6225a4348d1SPeter Crosthwaite qemu_fdt_setprop_phandle(fdt, pci, "interrupt-parent", mpic);
6235a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, pci, "interrupts", 24, 2);
6245a4348d1SPeter Crosthwaite qemu_fdt_setprop_cells(fdt, pci, "bus-range", 0, 255);
6254a18e7c9SScott Wood for (i = 0; i < 14; i++) {
6264a18e7c9SScott Wood pci_ranges[i] = cpu_to_be32(pci_ranges[i]);
6274a18e7c9SScott Wood }
6285a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, pci, "fsl,msi", msi_ph);
6295a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, pci, "ranges", pci_ranges, sizeof(pci_ranges));
6302eaaac1fSAlexander Graf qemu_fdt_setprop_cells(fdt, pci, "reg",
63103f04809SIgor Mammedov (pmc->ccsrbar_base + MPC8544_PCI_REGS_OFFSET) >> 32,
63203f04809SIgor Mammedov (pmc->ccsrbar_base + MPC8544_PCI_REGS_OFFSET),
6332eaaac1fSAlexander Graf 0, 0x1000);
6345a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, pci, "clock-frequency", 66666666);
6355a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, pci, "#interrupt-cells", 1);
6365a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, pci, "#size-cells", 2);
6375a4348d1SPeter Crosthwaite qemu_fdt_setprop_cell(fdt, pci, "#address-cells", 3);
6385a4348d1SPeter Crosthwaite qemu_fdt_setprop_string(fdt, "/aliases", "pci0", pci);
6392fb513d3SGreg Kurz g_free(pci);
6404a18e7c9SScott Wood
64103f04809SIgor Mammedov if (pmc->has_mpc8xxx_gpio) {
642b88e77f4SAlexander Graf create_dt_mpc8xxx_gpio(fdt, soc, mpic);
643b88e77f4SAlexander Graf }
6442fb513d3SGreg Kurz g_free(soc);
645b88e77f4SAlexander Graf
646a3fc8396SIgor Mammedov platform_bus_create_devtree(pms, fdt, mpic);
6470998fcb3SBernhard Beschow
6482fb513d3SGreg Kurz g_free(mpic);
649f7087343SAlexander Graf
65003f04809SIgor Mammedov pmc->fixup_devtree(fdt);
651e6eaabebSScott Wood
652e6eaabebSScott Wood if (toplevel_compat) {
6535a4348d1SPeter Crosthwaite qemu_fdt_setprop(fdt, "/", "compatible", toplevel_compat,
654e6eaabebSScott Wood strlen(toplevel_compat) + 1);
655e6eaabebSScott Wood }
656e6eaabebSScott Wood
6574a18e7c9SScott Wood done:
65828290f37SAlexander Graf if (!dry_run) {
6595a4348d1SPeter Crosthwaite qemu_fdt_dumpdtb(fdt, fdt_size);
66028290f37SAlexander Graf cpu_physical_memory_write(addr, fdt, fdt_size);
661891d51beSBernhard Beschow
662891d51beSBernhard Beschow /* Set machine->fdt for 'dumpdtb' QMP/HMP command */
663891d51beSBernhard Beschow g_free(machine->fdt);
664891d51beSBernhard Beschow machine->fdt = fdt;
665891d51beSBernhard Beschow } else {
666891d51beSBernhard Beschow g_free(fdt);
6674a18e7c9SScott Wood }
6684a18e7c9SScott Wood ret = fdt_size;
6694a18e7c9SScott Wood
6704a18e7c9SScott Wood out:
671347dd79dSAlexander Graf g_free(pci_map);
6724a18e7c9SScott Wood
6734a18e7c9SScott Wood return ret;
6744a18e7c9SScott Wood }
6754a18e7c9SScott Wood
67628290f37SAlexander Graf typedef struct DeviceTreeParams {
67703f04809SIgor Mammedov PPCE500MachineState *machine;
67828290f37SAlexander Graf hwaddr addr;
67928290f37SAlexander Graf hwaddr initrd_base;
68028290f37SAlexander Graf hwaddr initrd_size;
681903585deSAlexander Graf hwaddr kernel_base;
682903585deSAlexander Graf hwaddr kernel_size;
683f7087343SAlexander Graf Notifier notifier;
68428290f37SAlexander Graf } DeviceTreeParams;
68528290f37SAlexander Graf
ppce500_reset_device_tree(void * opaque)68628290f37SAlexander Graf static void ppce500_reset_device_tree(void *opaque)
68728290f37SAlexander Graf {
68828290f37SAlexander Graf DeviceTreeParams *p = opaque;
68903f04809SIgor Mammedov ppce500_load_device_tree(p->machine, p->addr, p->initrd_base,
690903585deSAlexander Graf p->initrd_size, p->kernel_base, p->kernel_size,
691903585deSAlexander Graf false);
69228290f37SAlexander Graf }
69328290f37SAlexander Graf
ppce500_init_notify(Notifier * notifier,void * data)694f7087343SAlexander Graf static void ppce500_init_notify(Notifier *notifier, void *data)
695f7087343SAlexander Graf {
696f7087343SAlexander Graf DeviceTreeParams *p = container_of(notifier, DeviceTreeParams, notifier);
697f7087343SAlexander Graf ppce500_reset_device_tree(p);
698f7087343SAlexander Graf }
699f7087343SAlexander Graf
ppce500_prep_device_tree(PPCE500MachineState * machine,hwaddr addr,hwaddr initrd_base,hwaddr initrd_size,hwaddr kernel_base,hwaddr kernel_size)70003f04809SIgor Mammedov static int ppce500_prep_device_tree(PPCE500MachineState *machine,
70128290f37SAlexander Graf hwaddr addr,
70228290f37SAlexander Graf hwaddr initrd_base,
703903585deSAlexander Graf hwaddr initrd_size,
704903585deSAlexander Graf hwaddr kernel_base,
705903585deSAlexander Graf hwaddr kernel_size)
70628290f37SAlexander Graf {
70728290f37SAlexander Graf DeviceTreeParams *p = g_new(DeviceTreeParams, 1);
7083ef96221SMarcel Apfelbaum p->machine = machine;
70928290f37SAlexander Graf p->addr = addr;
71028290f37SAlexander Graf p->initrd_base = initrd_base;
71128290f37SAlexander Graf p->initrd_size = initrd_size;
712903585deSAlexander Graf p->kernel_base = kernel_base;
713903585deSAlexander Graf p->kernel_size = kernel_size;
71428290f37SAlexander Graf
7156ec65b69SMaksim Kostin qemu_register_reset_nosnapshotload(ppce500_reset_device_tree, p);
716f7087343SAlexander Graf p->notifier.notify = ppce500_init_notify;
717f7087343SAlexander Graf qemu_add_machine_init_done_notifier(&p->notifier);
71828290f37SAlexander Graf
71928290f37SAlexander Graf /* Issue the device tree loader once, so that we get the size of the blob */
72003f04809SIgor Mammedov return ppce500_load_device_tree(machine, addr, initrd_base, initrd_size,
72103f04809SIgor Mammedov kernel_base, kernel_size, true);
72228290f37SAlexander Graf }
72328290f37SAlexander Graf
booke206_page_size_to_tlb(uint64_t size)724a36848ffSAaron Larson hwaddr booke206_page_size_to_tlb(uint64_t size)
7254a18e7c9SScott Wood {
726ab3dd749SPhilippe Mathieu-Daudé return 63 - clz64(size / KiB);
7274a18e7c9SScott Wood }
7284a18e7c9SScott Wood
booke206_initial_map_tsize(CPUPPCState * env)729cefd3cdbSBharat Bhushan static int booke206_initial_map_tsize(CPUPPCState *env)
7304a18e7c9SScott Wood {
7314a18e7c9SScott Wood struct boot_info *bi = env->load_info;
732cefd3cdbSBharat Bhushan hwaddr dt_end;
7334a18e7c9SScott Wood int ps;
7344a18e7c9SScott Wood
7354a18e7c9SScott Wood /* Our initial TLB entry needs to cover everything from 0 to
7364a18e7c9SScott Wood the device tree top */
7374a18e7c9SScott Wood dt_end = bi->dt_base + bi->dt_size;
7384a18e7c9SScott Wood ps = booke206_page_size_to_tlb(dt_end) + 1;
739fb37c302SAlexander Graf if (ps & 1) {
740fb37c302SAlexander Graf /* e500v2 can only do even TLB size bits */
741fb37c302SAlexander Graf ps++;
742fb37c302SAlexander Graf }
743cefd3cdbSBharat Bhushan return ps;
744cefd3cdbSBharat Bhushan }
745cefd3cdbSBharat Bhushan
mmubooke_initial_mapsize(CPUPPCState * env)746cefd3cdbSBharat Bhushan static uint64_t mmubooke_initial_mapsize(CPUPPCState *env)
747cefd3cdbSBharat Bhushan {
748cefd3cdbSBharat Bhushan int tsize;
749cefd3cdbSBharat Bhushan
750cefd3cdbSBharat Bhushan tsize = booke206_initial_map_tsize(env);
751cefd3cdbSBharat Bhushan return (1ULL << 10 << tsize);
752cefd3cdbSBharat Bhushan }
753cefd3cdbSBharat Bhushan
754320c5ad8SBernhard Beschow /* Create -kernel TLB entries for BookE. */
mmubooke_create_initial_mapping(CPUPPCState * env)755cefd3cdbSBharat Bhushan static void mmubooke_create_initial_mapping(CPUPPCState *env)
756cefd3cdbSBharat Bhushan {
757cefd3cdbSBharat Bhushan ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0);
758cefd3cdbSBharat Bhushan hwaddr size;
759cefd3cdbSBharat Bhushan int ps;
760cefd3cdbSBharat Bhushan
761cefd3cdbSBharat Bhushan ps = booke206_initial_map_tsize(env);
7624a18e7c9SScott Wood size = (ps << MAS1_TSIZE_SHIFT);
7634a18e7c9SScott Wood tlb->mas1 = MAS1_VALID | size;
7644a18e7c9SScott Wood tlb->mas2 = 0;
7654a18e7c9SScott Wood tlb->mas7_3 = 0;
7664a18e7c9SScott Wood tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
7674a18e7c9SScott Wood
76805739977SPhilippe Mathieu-Daudé #ifdef CONFIG_KVM
7694a18e7c9SScott Wood env->tlb_dirty = true;
77005739977SPhilippe Mathieu-Daudé #endif
7714a18e7c9SScott Wood }
7724a18e7c9SScott Wood
ppce500_cpu_reset_sec(void * opaque)773b3305981SScott Wood static void ppce500_cpu_reset_sec(void *opaque)
7744a18e7c9SScott Wood {
7754a18e7c9SScott Wood PowerPCCPU *cpu = opaque;
776259186a7SAndreas Färber CPUState *cs = CPU(cpu);
7774a18e7c9SScott Wood
778259186a7SAndreas Färber cpu_reset(cs);
7794a18e7c9SScott Wood
78027103424SAndreas Färber cs->exception_index = EXCP_HLT;
7814a18e7c9SScott Wood }
7824a18e7c9SScott Wood
ppce500_cpu_reset(void * opaque)783b3305981SScott Wood static void ppce500_cpu_reset(void *opaque)
7844a18e7c9SScott Wood {
7854a18e7c9SScott Wood PowerPCCPU *cpu = opaque;
786259186a7SAndreas Färber CPUState *cs = CPU(cpu);
7874a18e7c9SScott Wood CPUPPCState *env = &cpu->env;
7884a18e7c9SScott Wood struct boot_info *bi = env->load_info;
7894a18e7c9SScott Wood
790259186a7SAndreas Färber cpu_reset(cs);
7914a18e7c9SScott Wood
7924a18e7c9SScott Wood /* Set initial guest state. */
793259186a7SAndreas Färber cs->halted = 0;
794ab3dd749SPhilippe Mathieu-Daudé env->gpr[1] = (16 * MiB) - 8;
7954a18e7c9SScott Wood env->gpr[3] = bi->dt_base;
796cefd3cdbSBharat Bhushan env->gpr[4] = 0;
797cefd3cdbSBharat Bhushan env->gpr[5] = 0;
798cefd3cdbSBharat Bhushan env->gpr[6] = EPAPR_MAGIC;
799cefd3cdbSBharat Bhushan env->gpr[7] = mmubooke_initial_mapsize(env);
800cefd3cdbSBharat Bhushan env->gpr[8] = 0;
801cefd3cdbSBharat Bhushan env->gpr[9] = 0;
8024a18e7c9SScott Wood env->nip = bi->entry;
8034a18e7c9SScott Wood mmubooke_create_initial_mapping(env);
8044a18e7c9SScott Wood }
8054a18e7c9SScott Wood
ppce500_init_mpic_qemu(PPCE500MachineState * pms,IrqLines * irqs)80603f04809SIgor Mammedov static DeviceState *ppce500_init_mpic_qemu(PPCE500MachineState *pms,
8072104d4f5SGreg Kurz IrqLines *irqs)
80882fc73b6SScott Wood {
80982fc73b6SScott Wood DeviceState *dev;
81082fc73b6SScott Wood SysBusDevice *s;
81182fc73b6SScott Wood int i, j, k;
81203f04809SIgor Mammedov MachineState *machine = MACHINE(pms);
813fe6b6346SLike Xu unsigned int smp_cpus = machine->smp.cpus;
81403f04809SIgor Mammedov const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(pms);
81582fc73b6SScott Wood
8163e80f690SMarkus Armbruster dev = qdev_new(TYPE_OPENPIC);
817d2623129SMarkus Armbruster object_property_add_child(OBJECT(machine), "pic", OBJECT(dev));
81803f04809SIgor Mammedov qdev_prop_set_uint32(dev, "model", pmc->mpic_version);
819d85937e6SScott Wood qdev_prop_set_uint32(dev, "nb_cpus", smp_cpus);
820d85937e6SScott Wood
82182fc73b6SScott Wood s = SYS_BUS_DEVICE(dev);
8223c6ef471SMarkus Armbruster sysbus_realize_and_unref(s, &error_fatal);
82382fc73b6SScott Wood
82482fc73b6SScott Wood k = 0;
82582fc73b6SScott Wood for (i = 0; i < smp_cpus; i++) {
82682fc73b6SScott Wood for (j = 0; j < OPENPIC_OUTPUT_NB; j++) {
8272104d4f5SGreg Kurz sysbus_connect_irq(s, k++, irqs[i].irq[j]);
82882fc73b6SScott Wood }
82982fc73b6SScott Wood }
83082fc73b6SScott Wood
831d85937e6SScott Wood return dev;
832d85937e6SScott Wood }
833d85937e6SScott Wood
ppce500_init_mpic_kvm(const PPCE500MachineClass * pmc,IrqLines * irqs,Error ** errp)83403f04809SIgor Mammedov static DeviceState *ppce500_init_mpic_kvm(const PPCE500MachineClass *pmc,
8352104d4f5SGreg Kurz IrqLines *irqs, Error **errp)
836d85937e6SScott Wood {
83786d9ff28SPhilippe Mathieu-Daudé #ifdef CONFIG_KVM
838d85937e6SScott Wood DeviceState *dev;
839d85937e6SScott Wood CPUState *cs;
840d85937e6SScott Wood
8413e80f690SMarkus Armbruster dev = qdev_new(TYPE_KVM_OPENPIC);
84203f04809SIgor Mammedov qdev_prop_set_uint32(dev, "model", pmc->mpic_version);
843d85937e6SScott Wood
844668f62ecSMarkus Armbruster if (!sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), errp)) {
845fe656ebdSMarkus Armbruster object_unparent(OBJECT(dev));
846d85937e6SScott Wood return NULL;
847d85937e6SScott Wood }
848d85937e6SScott Wood
849bdc44640SAndreas Färber CPU_FOREACH(cs) {
850d85937e6SScott Wood if (kvm_openpic_connect_vcpu(dev, cs)) {
851d85937e6SScott Wood fprintf(stderr, "%s: failed to connect vcpu to irqchip\n",
852d85937e6SScott Wood __func__);
853d85937e6SScott Wood abort();
854d85937e6SScott Wood }
855d85937e6SScott Wood }
856d85937e6SScott Wood
857d85937e6SScott Wood return dev;
85886d9ff28SPhilippe Mathieu-Daudé #else
85986d9ff28SPhilippe Mathieu-Daudé g_assert_not_reached();
86086d9ff28SPhilippe Mathieu-Daudé #endif
861d85937e6SScott Wood }
862d85937e6SScott Wood
ppce500_init_mpic(PPCE500MachineState * pms,MemoryRegion * ccsr,IrqLines * irqs)86303f04809SIgor Mammedov static DeviceState *ppce500_init_mpic(PPCE500MachineState *pms,
864c91c187fSMichael Davidsaver MemoryRegion *ccsr,
8652104d4f5SGreg Kurz IrqLines *irqs)
866d85937e6SScott Wood {
86703f04809SIgor Mammedov const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(pms);
868d85937e6SScott Wood DeviceState *dev = NULL;
869d85937e6SScott Wood SysBusDevice *s;
870d85937e6SScott Wood
871d85937e6SScott Wood if (kvm_enabled()) {
872fe656ebdSMarkus Armbruster Error *err = NULL;
873d85937e6SScott Wood
8744376c40dSPaolo Bonzini if (kvm_kernel_irqchip_allowed()) {
87503f04809SIgor Mammedov dev = ppce500_init_mpic_kvm(pmc, irqs, &err);
876d85937e6SScott Wood }
8774376c40dSPaolo Bonzini if (kvm_kernel_irqchip_required() && !dev) {
878c29b77f9SMarkus Armbruster error_reportf_err(err,
879c29b77f9SMarkus Armbruster "kernel_irqchip requested but unavailable: ");
880fe656ebdSMarkus Armbruster exit(1);
881d85937e6SScott Wood }
882d85937e6SScott Wood }
883d85937e6SScott Wood
884d85937e6SScott Wood if (!dev) {
88503f04809SIgor Mammedov dev = ppce500_init_mpic_qemu(pms, irqs);
886d85937e6SScott Wood }
887d85937e6SScott Wood
888d85937e6SScott Wood s = SYS_BUS_DEVICE(dev);
88982fc73b6SScott Wood memory_region_add_subregion(ccsr, MPC8544_MPIC_REGS_OFFSET,
89082fc73b6SScott Wood s->mmio[0].memory);
89182fc73b6SScott Wood
892c91c187fSMichael Davidsaver return dev;
89382fc73b6SScott Wood }
89482fc73b6SScott Wood
ppce500_power_off(void * opaque,int line,int on)895016f7758SAlexander Graf static void ppce500_power_off(void *opaque, int line, int on)
896016f7758SAlexander Graf {
897016f7758SAlexander Graf if (on) {
898cf83f140SEric Blake qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
899016f7758SAlexander Graf }
900016f7758SAlexander Graf }
901016f7758SAlexander Graf
ppce500_init(MachineState * machine)90203f04809SIgor Mammedov void ppce500_init(MachineState *machine)
9034a18e7c9SScott Wood {
9044a18e7c9SScott Wood MemoryRegion *address_space_mem = get_system_memory();
90503f04809SIgor Mammedov PPCE500MachineState *pms = PPCE500_MACHINE(machine);
90603f04809SIgor Mammedov const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(machine);
907053b7086SThomas Huth MachineClass *mc = MACHINE_CLASS(pmc);
9084a18e7c9SScott Wood PCIBus *pci_bus;
9094a18e7c9SScott Wood CPUPPCState *env = NULL;
9103812c71fSAlexander Graf uint64_t loadaddr;
9113812c71fSAlexander Graf hwaddr kernel_base = -1LL;
9123812c71fSAlexander Graf int kernel_size = 0;
9133812c71fSAlexander Graf hwaddr dt_base = 0;
9143812c71fSAlexander Graf hwaddr initrd_base = 0;
9153812c71fSAlexander Graf int initrd_size = 0;
9163812c71fSAlexander Graf hwaddr cur_base = 0;
9173812c71fSAlexander Graf char *filename;
9188d622594SDavid Engraf const char *payload_name;
9198d622594SDavid Engraf bool kernel_as_payload;
9203812c71fSAlexander Graf hwaddr bios_entry = 0;
9218d622594SDavid Engraf target_long payload_size;
922a80fc80eSBernhard Beschow struct boot_info *boot_info = NULL;
9233812c71fSAlexander Graf int dt_size;
92482fc73b6SScott Wood int i;
925fe6b6346SLike Xu unsigned int smp_cpus = machine->smp.cpus;
926d575a6ceSBharat Bhushan /* irq num for pin INTA, INTB, INTC and INTD is 1, 2, 3 and
927d575a6ceSBharat Bhushan * 4 respectively */
928d575a6ceSBharat Bhushan unsigned int pci_irq_nrs[PCI_NUM_PINS] = {1, 2, 3, 4};
9292104d4f5SGreg Kurz IrqLines *irqs;
930c91c187fSMichael Davidsaver DeviceState *dev, *mpicdev;
93163e4bf8eSBernhard Beschow DriveInfo *dinfo;
9324a18e7c9SScott Wood CPUPPCState *firstenv = NULL;
9333eddc1beSBharat Bhushan MemoryRegion *ccsr_addr_space;
934dffb1dc2SBharat Bhushan SysBusDevice *s;
9353eddc1beSBharat Bhushan PPCE500CCSRState *ccsr;
9367abb479cSAndrew Randrianasulu I2CBus *i2c;
9374a18e7c9SScott Wood
9382104d4f5SGreg Kurz irqs = g_new0(IrqLines, smp_cpus);
9394a18e7c9SScott Wood for (i = 0; i < smp_cpus; i++) {
9404a18e7c9SScott Wood PowerPCCPU *cpu;
94155e5c285SAndreas Färber CPUState *cs;
9424a18e7c9SScott Wood
943a2c93f06SThiago Jung Bauermann cpu = POWERPC_CPU(object_new(machine->cpu_type));
9444a18e7c9SScott Wood env = &cpu->env;
94555e5c285SAndreas Färber cs = CPU(cpu);
9464a18e7c9SScott Wood
94700469dc3SValentin Plotkin if (env->mmu_model != POWERPC_MMU_BOOKE206) {
9486f76b817SAlistair Francis error_report("MMU model %i not supported by this machine",
94900469dc3SValentin Plotkin env->mmu_model);
95000469dc3SValentin Plotkin exit(1);
95100469dc3SValentin Plotkin }
95200469dc3SValentin Plotkin
953a2c93f06SThiago Jung Bauermann /*
954a2c93f06SThiago Jung Bauermann * Secondary CPU starts in halted state for now. Needs to change
955a2c93f06SThiago Jung Bauermann * when implementing non-kernel boot.
956a2c93f06SThiago Jung Bauermann */
957a2c93f06SThiago Jung Bauermann object_property_set_bool(OBJECT(cs), "start-powered-off", i != 0,
958287fa323SPhilippe Mathieu-Daudé &error_abort);
959a2c93f06SThiago Jung Bauermann qdev_realize_and_unref(DEVICE(cs), NULL, &error_fatal);
960a2c93f06SThiago Jung Bauermann
9614a18e7c9SScott Wood if (!firstenv) {
9624a18e7c9SScott Wood firstenv = env;
9634a18e7c9SScott Wood }
9644a18e7c9SScott Wood
9655e66cd0cSCédric Le Goater irqs[i].irq[OPENPIC_OUTPUT_INT] =
9665e66cd0cSCédric Le Goater qdev_get_gpio_in(DEVICE(cpu), PPCE500_INPUT_INT);
9675e66cd0cSCédric Le Goater irqs[i].irq[OPENPIC_OUTPUT_CINT] =
9685e66cd0cSCédric Le Goater qdev_get_gpio_in(DEVICE(cpu), PPCE500_INPUT_CINT);
9696a450df9SAlexander Graf env->spr_cb[SPR_BOOKE_PIR].default_value = cs->cpu_index = i;
97003f04809SIgor Mammedov env->mpic_iack = pmc->ccsrbar_base + MPC8544_MPIC_REGS_OFFSET + 0xa0;
9714a18e7c9SScott Wood
9720c36ab71SBin Meng ppc_booke_timers_init(cpu, PLATFORM_CLK_FREQ_HZ, PPC_TIMER_E500);
9734a18e7c9SScott Wood
9744a18e7c9SScott Wood /* Register reset handler */
9754a18e7c9SScott Wood if (!i) {
9764a18e7c9SScott Wood /* Primary CPU */
977b21e2380SMarkus Armbruster boot_info = g_new0(struct boot_info, 1);
978b3305981SScott Wood qemu_register_reset(ppce500_cpu_reset, cpu);
9794a18e7c9SScott Wood env->load_info = boot_info;
9804a18e7c9SScott Wood } else {
9814a18e7c9SScott Wood /* Secondary CPUs */
982b3305981SScott Wood qemu_register_reset(ppce500_cpu_reset_sec, cpu);
9834a18e7c9SScott Wood }
9844a18e7c9SScott Wood }
9854a18e7c9SScott Wood
9864a18e7c9SScott Wood env = firstenv;
9874a18e7c9SScott Wood
9883538e846SIgor Mammedov if (!QEMU_IS_ALIGNED(machine->ram_size, RAM_SIZES_ALIGN)) {
9893538e846SIgor Mammedov error_report("RAM size must be multiple of %" PRIu64, RAM_SIZES_ALIGN);
9903538e846SIgor Mammedov exit(EXIT_FAILURE);
9913538e846SIgor Mammedov }
9924a18e7c9SScott Wood
9934a18e7c9SScott Wood /* Register Memory */
99497316645SIgor Mammedov memory_region_add_subregion(address_space_mem, 0, machine->ram);
9954a18e7c9SScott Wood
9963e80f690SMarkus Armbruster dev = qdev_new("e500-ccsr");
9971a3e6528SBernhard Beschow object_property_add_child(OBJECT(machine), "e500-ccsr", OBJECT(dev));
9983c6ef471SMarkus Armbruster sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
9993eddc1beSBharat Bhushan ccsr = CCSR(dev);
10003eddc1beSBharat Bhushan ccsr_addr_space = &ccsr->ccsr_space;
100103f04809SIgor Mammedov memory_region_add_subregion(address_space_mem, pmc->ccsrbar_base,
10023eddc1beSBharat Bhushan ccsr_addr_space);
1003dffb1dc2SBharat Bhushan
100403f04809SIgor Mammedov mpicdev = ppce500_init_mpic(pms, ccsr_addr_space, irqs);
1005ef0efa1aSGan Qixin g_free(irqs);
10064a18e7c9SScott Wood
10074a18e7c9SScott Wood /* Serial */
10089bca0edbSPeter Maydell if (serial_hd(0)) {
10093eddc1beSBharat Bhushan serial_mm_init(ccsr_addr_space, MPC8544_SERIAL0_REGS_OFFSET,
1010c91c187fSMichael Davidsaver 0, qdev_get_gpio_in(mpicdev, 42), 399193,
10119bca0edbSPeter Maydell serial_hd(0), DEVICE_BIG_ENDIAN);
10124a18e7c9SScott Wood }
10134a18e7c9SScott Wood
10149bca0edbSPeter Maydell if (serial_hd(1)) {
10153eddc1beSBharat Bhushan serial_mm_init(ccsr_addr_space, MPC8544_SERIAL1_REGS_OFFSET,
1016c91c187fSMichael Davidsaver 0, qdev_get_gpio_in(mpicdev, 42), 399193,
10179bca0edbSPeter Maydell serial_hd(1), DEVICE_BIG_ENDIAN);
10184a18e7c9SScott Wood }
10193f288c4bSPhilippe Mathieu-Daudé
10207abb479cSAndrew Randrianasulu /* I2C */
10213e80f690SMarkus Armbruster dev = qdev_new("mpc-i2c");
10227abb479cSAndrew Randrianasulu s = SYS_BUS_DEVICE(dev);
10233c6ef471SMarkus Armbruster sysbus_realize_and_unref(s, &error_fatal);
10247abb479cSAndrew Randrianasulu sysbus_connect_irq(s, 0, qdev_get_gpio_in(mpicdev, MPC8544_I2C_IRQ));
10257abb479cSAndrew Randrianasulu memory_region_add_subregion(ccsr_addr_space, MPC8544_I2C_REGS_OFFSET,
10267abb479cSAndrew Randrianasulu sysbus_mmio_get_region(s, 0));
10277abb479cSAndrew Randrianasulu i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c");
10281373b15bSPhilippe Mathieu-Daudé i2c_slave_create_simple(i2c, "ds1338", RTC_REGS_OFFSET);
10297abb479cSAndrew Randrianasulu
10303f288c4bSPhilippe Mathieu-Daudé /* eSDHC */
10313f288c4bSPhilippe Mathieu-Daudé if (pmc->has_esdhc) {
10324e921beaSBernhard Beschow dev = qdev_new(TYPE_UNIMPLEMENTED_DEVICE);
10334e921beaSBernhard Beschow qdev_prop_set_string(dev, "name", "esdhc");
10344e921beaSBernhard Beschow qdev_prop_set_uint64(dev, "size", MPC85XX_ESDHC_REGS_SIZE);
10354e921beaSBernhard Beschow s = SYS_BUS_DEVICE(dev);
10364e921beaSBernhard Beschow sysbus_realize_and_unref(s, &error_fatal);
10374e921beaSBernhard Beschow memory_region_add_subregion(ccsr_addr_space, MPC85XX_ESDHC_REGS_OFFSET,
10384e921beaSBernhard Beschow sysbus_mmio_get_region(s, 0));
10393f288c4bSPhilippe Mathieu-Daudé
10403f288c4bSPhilippe Mathieu-Daudé /*
10413f288c4bSPhilippe Mathieu-Daudé * Compatible with:
10423f288c4bSPhilippe Mathieu-Daudé * - SD Host Controller Specification Version 2.0 Part A2
10433f288c4bSPhilippe Mathieu-Daudé * (See MPC8569E Reference Manual)
10443f288c4bSPhilippe Mathieu-Daudé */
10453f288c4bSPhilippe Mathieu-Daudé dev = qdev_new(TYPE_SYSBUS_SDHCI);
10463f288c4bSPhilippe Mathieu-Daudé qdev_prop_set_uint8(dev, "sd-spec-version", 2);
10473f288c4bSPhilippe Mathieu-Daudé qdev_prop_set_uint8(dev, "endianness", DEVICE_BIG_ENDIAN);
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é }
10544a18e7c9SScott Wood
10554a18e7c9SScott Wood /* 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));
10614a18e7c9SScott Wood
10624a18e7c9SScott Wood /* 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
10764a18e7c9SScott Wood pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
10774a18e7c9SScott Wood if (!pci_bus)
10784a18e7c9SScott Wood printf("couldn't create PCI controller!\n");
10794a18e7c9SScott Wood
10804a18e7c9SScott Wood if (pci_bus) {
10814a18e7c9SScott Wood /* Register network interfaces. */
1082*36b6968dSDavid Woodhouse pci_init_nic_devices(pci_bus, mc->default_nic);
10834a18e7c9SScott Wood }
10844a18e7c9SScott Wood
10854a18e7c9SScott Wood /* Register spinning region */
108603f04809SIgor Mammedov sysbus_create_simple("e500-spin", pmc->spin_base, NULL);
10874a18e7c9SScott Wood
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,
11988d622594SDavid Engraf 1, 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);
12324a18e7c9SScott Wood if (kernel_size < 0) {
12336f76b817SAlistair Francis error_report("could not load kernel '%s'",
12343ef96221SMarcel Apfelbaum machine->kernel_filename);
12354a18e7c9SScott Wood exit(1);
12364a18e7c9SScott Wood }
1237528e536eSAlexander Graf
12383812c71fSAlexander Graf cur_base += kernel_size;
12394a18e7c9SScott Wood }
12404a18e7c9SScott Wood
12414a18e7c9SScott Wood /* 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);
12464a18e7c9SScott Wood
12474a18e7c9SScott Wood if (initrd_size < 0) {
12486f76b817SAlistair Francis error_report("could not load initial ram disk '%s'",
12493ef96221SMarcel Apfelbaum machine->initrd_filename);
12504a18e7c9SScott Wood exit(1);
12514a18e7c9SScott Wood }
1252528e536eSAlexander Graf
1253528e536eSAlexander Graf cur_base = initrd_base + initrd_size;
12544a18e7c9SScott Wood }
12554a18e7c9SScott Wood
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 }
12674a18e7c9SScott Wood
126803f04809SIgor Mammedov dt_size = ppce500_prep_device_tree(pms, dt_base,
1269903585deSAlexander Graf initrd_base, initrd_size,
12703812c71fSAlexander Graf kernel_base, kernel_size);
12714a18e7c9SScott Wood if (dt_size < 0) {
12726f76b817SAlistair Francis error_report("couldn't load device tree");
12734a18e7c9SScott Wood exit(1);
12744a18e7c9SScott Wood }
1275b8dec144SAlexander Graf assert(dt_size < DTB_MAX_SIZE);
12764a18e7c9SScott Wood
12773812c71fSAlexander Graf boot_info->entry = bios_entry;
12784a18e7c9SScott Wood boot_info->dt_base = dt_base;
12794a18e7c9SScott Wood boot_info->dt_size = dt_size;
12804a18e7c9SScott Wood }
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