xref: /qemu/hw/ppc/e500.c (revision 2fb513d3b1e3472ff02dc00e213db65bc56506cd)
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"
18da34e65cSMarkus Armbruster #include "qapi/error.h"
19e6eaabebSScott Wood #include "e500.h"
203eddc1beSBharat Bhushan #include "e500-ccsr.h"
211422e32dSPaolo Bonzini #include "net/net.h"
221de7afc9SPaolo Bonzini #include "qemu/config-file.h"
234a18e7c9SScott Wood #include "hw/hw.h"
240d09e41aSPaolo Bonzini #include "hw/char/serial.h"
25a2cb15b0SMichael S. Tsirkin #include "hw/pci/pci.h"
264a18e7c9SScott Wood #include "hw/boards.h"
279c17d615SPaolo Bonzini #include "sysemu/sysemu.h"
289c17d615SPaolo Bonzini #include "sysemu/kvm.h"
291db09b84Saurel32 #include "kvm_ppc.h"
309c17d615SPaolo Bonzini #include "sysemu/device_tree.h"
310d09e41aSPaolo Bonzini #include "hw/ppc/openpic.h"
328d085cf0SMark Cave-Ayland #include "hw/ppc/openpic_kvm.h"
330d09e41aSPaolo Bonzini #include "hw/ppc/ppc.h"
344a18e7c9SScott Wood #include "hw/loader.h"
35ca20cf32SBlue Swirl #include "elf.h"
364a18e7c9SScott Wood #include "hw/sysbus.h"
37022c62cbSPaolo Bonzini #include "exec/address-spaces.h"
381de7afc9SPaolo Bonzini #include "qemu/host-utils.h"
39922a01a0SMarkus Armbruster #include "qemu/option.h"
400d09e41aSPaolo Bonzini #include "hw/pci-host/ppce500.h"
41f7087343SAlexander Graf #include "qemu/error-report.h"
42f7087343SAlexander Graf #include "hw/platform-bus.h"
43fdfb7f2cSAlexander Graf #include "hw/net/fsl_etsec/etsec.h"
441db09b84Saurel32 
45cefd3cdbSBharat Bhushan #define EPAPR_MAGIC                (0x45504150)
461db09b84Saurel32 #define BINARY_DEVICE_TREE_FILE    "mpc8544ds.dtb"
479dd5eba1SScott Wood #define DTC_LOAD_PAD               0x1800000
4875bb6589SLiu Yu #define DTC_PAD_MASK               0xFFFFF
49b8dec144SAlexander Graf #define DTB_MAX_SIZE               (8 * 1024 * 1024)
5075bb6589SLiu Yu #define INITRD_LOAD_PAD            0x2000000
5175bb6589SLiu Yu #define INITRD_PAD_MASK            0xFFFFFF
521db09b84Saurel32 
531db09b84Saurel32 #define RAM_SIZES_ALIGN            (64UL << 20)
541db09b84Saurel32 
55b3305981SScott Wood /* TODO: parameterize */
56ed2bc496SAlexander Graf #define MPC8544_CCSRBAR_SIZE       0x00100000ULL
57dffb1dc2SBharat Bhushan #define MPC8544_MPIC_REGS_OFFSET   0x40000ULL
58a911b7a9SAlexander Graf #define MPC8544_MSI_REGS_OFFSET   0x41600ULL
59dffb1dc2SBharat Bhushan #define MPC8544_SERIAL0_REGS_OFFSET 0x4500ULL
60dffb1dc2SBharat Bhushan #define MPC8544_SERIAL1_REGS_OFFSET 0x4600ULL
61dffb1dc2SBharat Bhushan #define MPC8544_PCI_REGS_OFFSET    0x8000ULL
62ed2bc496SAlexander Graf #define MPC8544_PCI_REGS_SIZE      0x1000ULL
63dffb1dc2SBharat Bhushan #define MPC8544_UTIL_OFFSET        0xe0000ULL
64b88e77f4SAlexander Graf #define MPC8XXX_GPIO_OFFSET        0x000FF000ULL
6582e345f5SAmit Tomar #define MPC8XXX_GPIO_IRQ           47
661db09b84Saurel32 
673b989d49SAlexander Graf struct boot_info
683b989d49SAlexander Graf {
693b989d49SAlexander Graf     uint32_t dt_base;
70cba2026aSAlexander Graf     uint32_t dt_size;
713b989d49SAlexander Graf     uint32_t entry;
723b989d49SAlexander Graf };
733b989d49SAlexander Graf 
74347dd79dSAlexander Graf static uint32_t *pci_map_create(void *fdt, uint32_t mpic, int first_slot,
75347dd79dSAlexander Graf                                 int nr_slots, int *len)
760dbc0798SAlexander Graf {
77347dd79dSAlexander Graf     int i = 0;
78347dd79dSAlexander Graf     int slot;
79347dd79dSAlexander Graf     int pci_irq;
809e2c1298SAlexander Graf     int host_irq;
81347dd79dSAlexander Graf     int last_slot = first_slot + nr_slots;
82347dd79dSAlexander Graf     uint32_t *pci_map;
830dbc0798SAlexander Graf 
84347dd79dSAlexander Graf     *len = nr_slots * 4 * 7 * sizeof(uint32_t);
85347dd79dSAlexander Graf     pci_map = g_malloc(*len);
86347dd79dSAlexander Graf 
87347dd79dSAlexander Graf     for (slot = first_slot; slot < last_slot; slot++) {
88347dd79dSAlexander Graf         for (pci_irq = 0; pci_irq < 4; pci_irq++) {
89347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(slot << 11);
90347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(0x0);
91347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(0x0);
92347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(pci_irq + 1);
93347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(mpic);
949e2c1298SAlexander Graf             host_irq = ppce500_pci_map_irq_slot(slot, pci_irq);
959e2c1298SAlexander Graf             pci_map[i++] = cpu_to_be32(host_irq + 1);
96347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(0x1);
970dbc0798SAlexander Graf         }
980dbc0798SAlexander Graf     }
990dbc0798SAlexander Graf 
100347dd79dSAlexander Graf     assert((i * sizeof(uint32_t)) == *len);
101347dd79dSAlexander Graf 
102347dd79dSAlexander Graf     return pci_map;
103347dd79dSAlexander Graf }
104347dd79dSAlexander Graf 
105a053a7ceSAlexander Graf static void dt_serial_create(void *fdt, unsigned long long offset,
106a053a7ceSAlexander Graf                              const char *soc, const char *mpic,
107a053a7ceSAlexander Graf                              const char *alias, int idx, bool defcon)
108a053a7ceSAlexander Graf {
109*2fb513d3SGreg Kurz     char *ser;
110a053a7ceSAlexander Graf 
111*2fb513d3SGreg Kurz     ser = g_strdup_printf("%s/serial@%llx", soc, offset);
1125a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, ser);
1135a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, ser, "device_type", "serial");
1145a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, ser, "compatible", "ns16550");
1155a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, ser, "reg", offset, 0x100);
1165a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, ser, "cell-index", idx);
1175a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, ser, "clock-frequency", 0);
1185a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, ser, "interrupts", 42, 2);
1195a4348d1SPeter Crosthwaite     qemu_fdt_setprop_phandle(fdt, ser, "interrupt-parent", mpic);
1205a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, "/aliases", alias, ser);
121a053a7ceSAlexander Graf 
122a053a7ceSAlexander Graf     if (defcon) {
12390ee4e01SNikunj A Dadhania         /*
12490ee4e01SNikunj A Dadhania          * "linux,stdout-path" and "stdout" properties are deprecated by linux
12590ee4e01SNikunj A Dadhania          * kernel. New platforms should only use the "stdout-path" property. Set
12690ee4e01SNikunj A Dadhania          * the new property and continue using older property to remain
12790ee4e01SNikunj A Dadhania          * compatible with the existing firmware.
12890ee4e01SNikunj A Dadhania          */
1295a4348d1SPeter Crosthwaite         qemu_fdt_setprop_string(fdt, "/chosen", "linux,stdout-path", ser);
13090ee4e01SNikunj A Dadhania         qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", ser);
131a053a7ceSAlexander Graf     }
132*2fb513d3SGreg Kurz     g_free(ser);
133a053a7ceSAlexander Graf }
134a053a7ceSAlexander Graf 
135b88e77f4SAlexander Graf static void create_dt_mpc8xxx_gpio(void *fdt, const char *soc, const char *mpic)
136b88e77f4SAlexander Graf {
137b88e77f4SAlexander Graf     hwaddr mmio0 = MPC8XXX_GPIO_OFFSET;
138b88e77f4SAlexander Graf     int irq0 = MPC8XXX_GPIO_IRQ;
139b88e77f4SAlexander Graf     gchar *node = g_strdup_printf("%s/gpio@%"PRIx64, soc, mmio0);
140016f7758SAlexander Graf     gchar *poweroff = g_strdup_printf("%s/power-off", soc);
141016f7758SAlexander Graf     int gpio_ph;
142b88e77f4SAlexander Graf 
143b88e77f4SAlexander Graf     qemu_fdt_add_subnode(fdt, node);
144b88e77f4SAlexander Graf     qemu_fdt_setprop_string(fdt, node, "compatible", "fsl,qoriq-gpio");
145b88e77f4SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "reg", mmio0, 0x1000);
146b88e77f4SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "interrupts", irq0, 0x2);
147b88e77f4SAlexander Graf     qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", mpic);
148b88e77f4SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "#gpio-cells", 2);
149b88e77f4SAlexander Graf     qemu_fdt_setprop(fdt, node, "gpio-controller", NULL, 0);
150016f7758SAlexander Graf     gpio_ph = qemu_fdt_alloc_phandle(fdt);
151016f7758SAlexander Graf     qemu_fdt_setprop_cell(fdt, node, "phandle", gpio_ph);
152016f7758SAlexander Graf     qemu_fdt_setprop_cell(fdt, node, "linux,phandle", gpio_ph);
153016f7758SAlexander Graf 
154016f7758SAlexander Graf     /* Power Off Pin */
155016f7758SAlexander Graf     qemu_fdt_add_subnode(fdt, poweroff);
156016f7758SAlexander Graf     qemu_fdt_setprop_string(fdt, poweroff, "compatible", "gpio-poweroff");
157016f7758SAlexander Graf     qemu_fdt_setprop_cells(fdt, poweroff, "gpios", gpio_ph, 0, 0);
158b88e77f4SAlexander Graf 
159b88e77f4SAlexander Graf     g_free(node);
160016f7758SAlexander Graf     g_free(poweroff);
161b88e77f4SAlexander Graf }
162b88e77f4SAlexander Graf 
163f7087343SAlexander Graf typedef struct PlatformDevtreeData {
164f7087343SAlexander Graf     void *fdt;
165f7087343SAlexander Graf     const char *mpic;
166f7087343SAlexander Graf     int irq_start;
167f7087343SAlexander Graf     const char *node;
168f7087343SAlexander Graf     PlatformBusDevice *pbus;
169f7087343SAlexander Graf } PlatformDevtreeData;
170f7087343SAlexander Graf 
171fdfb7f2cSAlexander Graf static int create_devtree_etsec(SysBusDevice *sbdev, PlatformDevtreeData *data)
172fdfb7f2cSAlexander Graf {
173fdfb7f2cSAlexander Graf     eTSEC *etsec = ETSEC_COMMON(sbdev);
174fdfb7f2cSAlexander Graf     PlatformBusDevice *pbus = data->pbus;
175fdfb7f2cSAlexander Graf     hwaddr mmio0 = platform_bus_get_mmio_addr(pbus, sbdev, 0);
176fdfb7f2cSAlexander Graf     int irq0 = platform_bus_get_irqn(pbus, sbdev, 0);
177fdfb7f2cSAlexander Graf     int irq1 = platform_bus_get_irqn(pbus, sbdev, 1);
178fdfb7f2cSAlexander Graf     int irq2 = platform_bus_get_irqn(pbus, sbdev, 2);
179fdfb7f2cSAlexander Graf     gchar *node = g_strdup_printf("/platform/ethernet@%"PRIx64, mmio0);
180fdfb7f2cSAlexander Graf     gchar *group = g_strdup_printf("%s/queue-group", node);
181fdfb7f2cSAlexander Graf     void *fdt = data->fdt;
182fdfb7f2cSAlexander Graf 
183fdfb7f2cSAlexander Graf     assert((int64_t)mmio0 >= 0);
184fdfb7f2cSAlexander Graf     assert(irq0 >= 0);
185fdfb7f2cSAlexander Graf     assert(irq1 >= 0);
186fdfb7f2cSAlexander Graf     assert(irq2 >= 0);
187fdfb7f2cSAlexander Graf 
188fdfb7f2cSAlexander Graf     qemu_fdt_add_subnode(fdt, node);
189fdfb7f2cSAlexander Graf     qemu_fdt_setprop_string(fdt, node, "device_type", "network");
190fdfb7f2cSAlexander Graf     qemu_fdt_setprop_string(fdt, node, "compatible", "fsl,etsec2");
191fdfb7f2cSAlexander Graf     qemu_fdt_setprop_string(fdt, node, "model", "eTSEC");
192fdfb7f2cSAlexander Graf     qemu_fdt_setprop(fdt, node, "local-mac-address", etsec->conf.macaddr.a, 6);
193fdfb7f2cSAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "fixed-link", 0, 1, 1000, 0, 0);
194fdfb7f2cSAlexander Graf 
195fdfb7f2cSAlexander Graf     qemu_fdt_add_subnode(fdt, group);
196fdfb7f2cSAlexander Graf     qemu_fdt_setprop_cells(fdt, group, "reg", mmio0, 0x1000);
197fdfb7f2cSAlexander Graf     qemu_fdt_setprop_cells(fdt, group, "interrupts",
198fdfb7f2cSAlexander Graf         data->irq_start + irq0, 0x2,
199fdfb7f2cSAlexander Graf         data->irq_start + irq1, 0x2,
200fdfb7f2cSAlexander Graf         data->irq_start + irq2, 0x2);
201fdfb7f2cSAlexander Graf 
202fdfb7f2cSAlexander Graf     g_free(node);
203fdfb7f2cSAlexander Graf     g_free(group);
204fdfb7f2cSAlexander Graf 
205fdfb7f2cSAlexander Graf     return 0;
206fdfb7f2cSAlexander Graf }
207fdfb7f2cSAlexander Graf 
2084f01a637SDavid Gibson static void sysbus_device_create_devtree(SysBusDevice *sbdev, void *opaque)
209f7087343SAlexander Graf {
210f7087343SAlexander Graf     PlatformDevtreeData *data = opaque;
211f7087343SAlexander Graf     bool matched = false;
212f7087343SAlexander Graf 
213fdfb7f2cSAlexander Graf     if (object_dynamic_cast(OBJECT(sbdev), TYPE_ETSEC_COMMON)) {
214fdfb7f2cSAlexander Graf         create_devtree_etsec(sbdev, data);
215fdfb7f2cSAlexander Graf         matched = true;
216fdfb7f2cSAlexander Graf     }
217fdfb7f2cSAlexander Graf 
218f7087343SAlexander Graf     if (!matched) {
219f7087343SAlexander Graf         error_report("Device %s is not supported by this machine yet.",
220f7087343SAlexander Graf                      qdev_fw_name(DEVICE(sbdev)));
221f7087343SAlexander Graf         exit(1);
222f7087343SAlexander Graf     }
223f7087343SAlexander Graf }
224f7087343SAlexander Graf 
22503f04809SIgor Mammedov static void platform_bus_create_devtree(const PPCE500MachineClass *pmc,
22603f04809SIgor Mammedov                                         void *fdt, const char *mpic)
227f7087343SAlexander Graf {
22803f04809SIgor Mammedov     gchar *node = g_strdup_printf("/platform@%"PRIx64, pmc->platform_bus_base);
229f7087343SAlexander Graf     const char platcomp[] = "qemu,platform\0simple-bus";
23003f04809SIgor Mammedov     uint64_t addr = pmc->platform_bus_base;
23103f04809SIgor Mammedov     uint64_t size = pmc->platform_bus_size;
23203f04809SIgor Mammedov     int irq_start = pmc->platform_bus_first_irq;
233f7087343SAlexander Graf     PlatformBusDevice *pbus;
234f7087343SAlexander Graf     DeviceState *dev;
235f7087343SAlexander Graf 
236f7087343SAlexander Graf     /* Create a /platform node that we can put all devices into */
237f7087343SAlexander Graf 
238f7087343SAlexander Graf     qemu_fdt_add_subnode(fdt, node);
239f7087343SAlexander Graf     qemu_fdt_setprop(fdt, node, "compatible", platcomp, sizeof(platcomp));
240f7087343SAlexander Graf 
241f7087343SAlexander Graf     /* Our platform bus region is less than 32bit big, so 1 cell is enough for
242f7087343SAlexander Graf        address and size */
243f7087343SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "#size-cells", 1);
244f7087343SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "#address-cells", 1);
245f7087343SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "ranges", 0, addr >> 32, addr, size);
246f7087343SAlexander Graf 
247f7087343SAlexander Graf     qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", mpic);
248f7087343SAlexander Graf 
249f7087343SAlexander Graf     dev = qdev_find_recursive(sysbus_get_default(), TYPE_PLATFORM_BUS_DEVICE);
250f7087343SAlexander Graf     pbus = PLATFORM_BUS_DEVICE(dev);
251f7087343SAlexander Graf 
252f7087343SAlexander Graf     /* We can only create dt nodes for dynamic devices when they're ready */
253f7087343SAlexander Graf     if (pbus->done_gathering) {
254f7087343SAlexander Graf         PlatformDevtreeData data = {
255f7087343SAlexander Graf             .fdt = fdt,
256f7087343SAlexander Graf             .mpic = mpic,
257f7087343SAlexander Graf             .irq_start = irq_start,
258f7087343SAlexander Graf             .node = node,
259f7087343SAlexander Graf             .pbus = pbus,
260f7087343SAlexander Graf         };
261f7087343SAlexander Graf 
262f7087343SAlexander Graf         /* Loop through all dynamic sysbus devices and create nodes for them */
263f7087343SAlexander Graf         foreach_dynamic_sysbus_device(sysbus_device_create_devtree, &data);
264f7087343SAlexander Graf     }
265f7087343SAlexander Graf 
266f7087343SAlexander Graf     g_free(node);
267f7087343SAlexander Graf }
268f7087343SAlexander Graf 
26903f04809SIgor Mammedov static int ppce500_load_device_tree(PPCE500MachineState *pms,
270a8170e5eSAvi Kivity                                     hwaddr addr,
271a8170e5eSAvi Kivity                                     hwaddr initrd_base,
27228290f37SAlexander Graf                                     hwaddr initrd_size,
273903585deSAlexander Graf                                     hwaddr kernel_base,
274903585deSAlexander Graf                                     hwaddr kernel_size,
27528290f37SAlexander Graf                                     bool dry_run)
2761db09b84Saurel32 {
27703f04809SIgor Mammedov     MachineState *machine = MACHINE(pms);
27803f04809SIgor Mammedov     const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(pms);
27928290f37SAlexander Graf     CPUPPCState *env = first_cpu->env_ptr;
280dbf916d8SAurelien Jarno     int ret = -1;
2813ef96221SMarcel Apfelbaum     uint64_t mem_reg_property[] = { 0, cpu_to_be64(machine->ram_size) };
2827ec632b4Spbrook     int fdt_size;
283dbf916d8SAurelien Jarno     void *fdt;
2845de6b46dSAlexander Graf     uint8_t hypercall[16];
285911d6e7aSAlexander Graf     uint32_t clock_freq = 400000000;
286911d6e7aSAlexander Graf     uint32_t tb_freq = 400000000;
287621d05e3SAlexander Graf     int i;
288ebb9518aSAlexander Graf     char compatible_sb[] = "fsl,mpc8544-immr\0simple-bus";
289*2fb513d3SGreg Kurz     char *soc;
290*2fb513d3SGreg Kurz     char *mpic;
29119ac9deaSAlexander Graf     uint32_t mpic_ph;
292a911b7a9SAlexander Graf     uint32_t msi_ph;
293*2fb513d3SGreg Kurz     char *gutil;
294*2fb513d3SGreg Kurz     char *pci;
295*2fb513d3SGreg Kurz     char *msi;
296347dd79dSAlexander Graf     uint32_t *pci_map = NULL;
297347dd79dSAlexander Graf     int len;
2983627757eSAlexander Graf     uint32_t pci_ranges[14] =
2993627757eSAlexander Graf         {
30003f04809SIgor Mammedov             0x2000000, 0x0, pmc->pci_mmio_bus_base,
30103f04809SIgor Mammedov             pmc->pci_mmio_base >> 32, pmc->pci_mmio_base,
3023627757eSAlexander Graf             0x0, 0x20000000,
3033627757eSAlexander Graf 
3043627757eSAlexander Graf             0x1000000, 0x0, 0x0,
30503f04809SIgor Mammedov             pmc->pci_pio_base >> 32, pmc->pci_pio_base,
3063627757eSAlexander Graf             0x0, 0x10000,
3073627757eSAlexander Graf         };
3082ff3de68SMarkus Armbruster     QemuOpts *machine_opts = qemu_get_machine_opts();
3092ff3de68SMarkus Armbruster     const char *dtb_file = qemu_opt_get(machine_opts, "dtb");
3102ff3de68SMarkus Armbruster     const char *toplevel_compat = qemu_opt_get(machine_opts, "dt_compatible");
311d1b93565SAlexander Graf 
312d1b93565SAlexander Graf     if (dtb_file) {
313d1b93565SAlexander Graf         char *filename;
314d1b93565SAlexander Graf         filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_file);
315d1b93565SAlexander Graf         if (!filename) {
316d1b93565SAlexander Graf             goto out;
317d1b93565SAlexander Graf         }
318d1b93565SAlexander Graf 
319d1b93565SAlexander Graf         fdt = load_device_tree(filename, &fdt_size);
3202343dd11SMichael Tokarev         g_free(filename);
321d1b93565SAlexander Graf         if (!fdt) {
322d1b93565SAlexander Graf             goto out;
323d1b93565SAlexander Graf         }
324d1b93565SAlexander Graf         goto done;
325d1b93565SAlexander Graf     }
3261db09b84Saurel32 
3272636fcb6SAlexander Graf     fdt = create_device_tree(&fdt_size);
3285cea8590SPaul Brook     if (fdt == NULL) {
3295cea8590SPaul Brook         goto out;
3305cea8590SPaul Brook     }
3311db09b84Saurel32 
3321db09b84Saurel32     /* Manipulate device tree in memory. */
3335a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 2);
3345a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 2);
33551b852b7SAlexander Graf 
3365a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, "/memory");
3375a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, "/memory", "device_type", "memory");
3385a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, "/memory", "reg", mem_reg_property,
3391db09b84Saurel32                      sizeof(mem_reg_property));
3401db09b84Saurel32 
3415a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, "/chosen");
3423b989d49SAlexander Graf     if (initrd_size) {
3435a4348d1SPeter Crosthwaite         ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start",
3441db09b84Saurel32                                     initrd_base);
3453b989d49SAlexander Graf         if (ret < 0) {
3461db09b84Saurel32             fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
3473b989d49SAlexander Graf         }
3481db09b84Saurel32 
3495a4348d1SPeter Crosthwaite         ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
3501db09b84Saurel32                                     (initrd_base + initrd_size));
3513b989d49SAlexander Graf         if (ret < 0) {
3521db09b84Saurel32             fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
3533b989d49SAlexander Graf         }
354903585deSAlexander Graf 
355903585deSAlexander Graf     }
356903585deSAlexander Graf 
357903585deSAlexander Graf     if (kernel_base != -1ULL) {
358903585deSAlexander Graf         qemu_fdt_setprop_cells(fdt, "/chosen", "qemu,boot-kernel",
359903585deSAlexander Graf                                      kernel_base >> 32, kernel_base,
360903585deSAlexander Graf                                      kernel_size >> 32, kernel_size);
3613b989d49SAlexander Graf     }
3621db09b84Saurel32 
3635a4348d1SPeter Crosthwaite     ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
3643ef96221SMarcel Apfelbaum                                       machine->kernel_cmdline);
3651db09b84Saurel32     if (ret < 0)
3661db09b84Saurel32         fprintf(stderr, "couldn't set /chosen/bootargs\n");
3671db09b84Saurel32 
3681db09b84Saurel32     if (kvm_enabled()) {
369911d6e7aSAlexander Graf         /* Read out host's frequencies */
370911d6e7aSAlexander Graf         clock_freq = kvmppc_get_clockfreq();
371911d6e7aSAlexander Graf         tb_freq = kvmppc_get_tbfreq();
3725de6b46dSAlexander Graf 
3735de6b46dSAlexander Graf         /* indicate KVM hypercall interface */
3745a4348d1SPeter Crosthwaite         qemu_fdt_add_subnode(fdt, "/hypervisor");
3755a4348d1SPeter Crosthwaite         qemu_fdt_setprop_string(fdt, "/hypervisor", "compatible",
3765de6b46dSAlexander Graf                                 "linux,kvm");
3775de6b46dSAlexander Graf         kvmppc_get_hypercall(env, hypercall, sizeof(hypercall));
3785a4348d1SPeter Crosthwaite         qemu_fdt_setprop(fdt, "/hypervisor", "hcall-instructions",
3795de6b46dSAlexander Graf                          hypercall, sizeof(hypercall));
3801a61a9aeSStuart Yoder         /* if KVM supports the idle hcall, set property indicating this */
3811a61a9aeSStuart Yoder         if (kvmppc_get_hasidle(env)) {
3825a4348d1SPeter Crosthwaite             qemu_fdt_setprop(fdt, "/hypervisor", "has-idle", NULL, 0);
3831a61a9aeSStuart Yoder         }
3841db09b84Saurel32     }
3851db09b84Saurel32 
386625e665bSAlexander Graf     /* Create CPU nodes */
3875a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, "/cpus");
3885a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 1);
3895a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0);
390625e665bSAlexander Graf 
3911e3debf0SAlexander Graf     /* We need to generate the cpu nodes in reverse order, so Linux can pick
3921e3debf0SAlexander Graf        the first node as boot node and be happy */
3931e3debf0SAlexander Graf     for (i = smp_cpus - 1; i >= 0; i--) {
394440c8152SAndreas Färber         CPUState *cpu;
395*2fb513d3SGreg Kurz         char *cpu_name;
39603f04809SIgor Mammedov         uint64_t cpu_release_addr = pmc->spin_base + (i * 0x20);
39710f25a46SAlexander Graf 
398440c8152SAndreas Färber         cpu = qemu_get_cpu(i);
39955e5c285SAndreas Färber         if (cpu == NULL) {
4001e3debf0SAlexander Graf             continue;
4011e3debf0SAlexander Graf         }
402440c8152SAndreas Färber         env = cpu->env_ptr;
4031e3debf0SAlexander Graf 
404*2fb513d3SGreg Kurz         cpu_name = g_strdup_printf("/cpus/PowerPC,8544@%x", i);
4055a4348d1SPeter Crosthwaite         qemu_fdt_add_subnode(fdt, cpu_name);
4065a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq);
4075a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq);
4085a4348d1SPeter Crosthwaite         qemu_fdt_setprop_string(fdt, cpu_name, "device_type", "cpu");
4096d536570SSam Bobroff         qemu_fdt_setprop_cell(fdt, cpu_name, "reg", i);
4105a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-line-size",
4111e3debf0SAlexander Graf                               env->dcache_line_size);
4125a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-line-size",
4131e3debf0SAlexander Graf                               env->icache_line_size);
4145a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-size", 0x8000);
4155a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-size", 0x8000);
4165a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "bus-frequency", 0);
41755e5c285SAndreas Färber         if (cpu->cpu_index) {
4185a4348d1SPeter Crosthwaite             qemu_fdt_setprop_string(fdt, cpu_name, "status", "disabled");
4195a4348d1SPeter Crosthwaite             qemu_fdt_setprop_string(fdt, cpu_name, "enable-method",
4205a4348d1SPeter Crosthwaite                                     "spin-table");
4215a4348d1SPeter Crosthwaite             qemu_fdt_setprop_u64(fdt, cpu_name, "cpu-release-addr",
4221d2e5c52SAlexander Graf                                  cpu_release_addr);
4231e3debf0SAlexander Graf         } else {
4245a4348d1SPeter Crosthwaite             qemu_fdt_setprop_string(fdt, cpu_name, "status", "okay");
4251e3debf0SAlexander Graf         }
426*2fb513d3SGreg Kurz         g_free(cpu_name);
4271db09b84Saurel32     }
4281db09b84Saurel32 
4295a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, "/aliases");
4305da96624SAlexander Graf     /* XXX These should go into their respective devices' code */
431*2fb513d3SGreg Kurz     soc = g_strdup_printf("/soc@%"PRIx64, pmc->ccsrbar_base);
4325a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, soc);
4335a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, soc, "device_type", "soc");
4345a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, soc, "compatible", compatible_sb,
435ebb9518aSAlexander Graf                      sizeof(compatible_sb));
4365a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, soc, "#address-cells", 1);
4375a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, soc, "#size-cells", 1);
4385a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, soc, "ranges", 0x0,
43903f04809SIgor Mammedov                            pmc->ccsrbar_base >> 32, pmc->ccsrbar_base,
4405da96624SAlexander Graf                            MPC8544_CCSRBAR_SIZE);
4415da96624SAlexander Graf     /* XXX should contain a reasonable value */
4425a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, soc, "bus-frequency", 0);
4435da96624SAlexander Graf 
444*2fb513d3SGreg Kurz     mpic = g_strdup_printf("%s/pic@%llx", soc, MPC8544_MPIC_REGS_OFFSET);
4455a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, mpic);
4465a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, mpic, "device_type", "open-pic");
4475a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, mpic, "compatible", "fsl,mpic");
4485a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_OFFSET,
449dffb1dc2SBharat Bhushan                            0x40000);
4505a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, mpic, "#address-cells", 0);
4515a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, mpic, "#interrupt-cells", 2);
4525a4348d1SPeter Crosthwaite     mpic_ph = qemu_fdt_alloc_phandle(fdt);
4535a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, mpic, "phandle", mpic_ph);
4545a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, mpic, "linux,phandle", mpic_ph);
4555a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, mpic, "interrupt-controller", NULL, 0);
45619ac9deaSAlexander Graf 
4570cfc6e8dSAlexander Graf     /*
4580cfc6e8dSAlexander Graf      * We have to generate ser1 first, because Linux takes the first
4590cfc6e8dSAlexander Graf      * device it finds in the dt as serial output device. And we generate
4600cfc6e8dSAlexander Graf      * devices in reverse order to the dt.
4610cfc6e8dSAlexander Graf      */
4629bca0edbSPeter Maydell     if (serial_hd(1)) {
463dffb1dc2SBharat Bhushan         dt_serial_create(fdt, MPC8544_SERIAL1_REGS_OFFSET,
464a053a7ceSAlexander Graf                          soc, mpic, "serial1", 1, false);
46579c0ff2cSAlexander Graf     }
46679c0ff2cSAlexander Graf 
4679bca0edbSPeter Maydell     if (serial_hd(0)) {
468dffb1dc2SBharat Bhushan         dt_serial_create(fdt, MPC8544_SERIAL0_REGS_OFFSET,
469a053a7ceSAlexander Graf                          soc, mpic, "serial0", 0, true);
47079c0ff2cSAlexander Graf     }
4710cfc6e8dSAlexander Graf 
472*2fb513d3SGreg Kurz     gutil = g_strdup_printf("%s/global-utilities@%llx", soc,
473dffb1dc2SBharat Bhushan                             MPC8544_UTIL_OFFSET);
4745a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, gutil);
4755a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, gutil, "compatible", "fsl,mpc8544-guts");
4765a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, gutil, "reg", MPC8544_UTIL_OFFSET, 0x1000);
4775a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, gutil, "fsl,has-rstcr", NULL, 0);
478*2fb513d3SGreg Kurz     g_free(gutil);
479f5038483SAlexander Graf 
480*2fb513d3SGreg Kurz     msi = g_strdup_printf("/%s/msi@%llx", soc, MPC8544_MSI_REGS_OFFSET);
4815a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, msi);
4825a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, msi, "compatible", "fsl,mpic-msi");
4835a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, msi, "reg", MPC8544_MSI_REGS_OFFSET, 0x200);
4845a4348d1SPeter Crosthwaite     msi_ph = qemu_fdt_alloc_phandle(fdt);
4855a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, msi, "msi-available-ranges", 0x0, 0x100);
4865a4348d1SPeter Crosthwaite     qemu_fdt_setprop_phandle(fdt, msi, "interrupt-parent", mpic);
4875a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, msi, "interrupts",
488a911b7a9SAlexander Graf         0xe0, 0x0,
489a911b7a9SAlexander Graf         0xe1, 0x0,
490a911b7a9SAlexander Graf         0xe2, 0x0,
491a911b7a9SAlexander Graf         0xe3, 0x0,
492a911b7a9SAlexander Graf         0xe4, 0x0,
493a911b7a9SAlexander Graf         0xe5, 0x0,
494a911b7a9SAlexander Graf         0xe6, 0x0,
495a911b7a9SAlexander Graf         0xe7, 0x0);
4965a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, msi, "phandle", msi_ph);
4975a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, msi, "linux,phandle", msi_ph);
498*2fb513d3SGreg Kurz     g_free(msi);
499a911b7a9SAlexander Graf 
500*2fb513d3SGreg Kurz     pci = g_strdup_printf("/pci@%llx",
50103f04809SIgor Mammedov                           pmc->ccsrbar_base + MPC8544_PCI_REGS_OFFSET);
5025a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, pci);
5035a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "cell-index", 0);
5045a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, pci, "compatible", "fsl,mpc8540-pci");
5055a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, pci, "device_type", "pci");
5065a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, pci, "interrupt-map-mask", 0xf800, 0x0,
5070dbc0798SAlexander Graf                            0x0, 0x7);
5085a4348d1SPeter Crosthwaite     pci_map = pci_map_create(fdt, qemu_fdt_get_phandle(fdt, mpic),
50903f04809SIgor Mammedov                              pmc->pci_first_slot, pmc->pci_nr_slots,
510492ec48dSAlexander Graf                              &len);
5115a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, pci, "interrupt-map", pci_map, len);
5125a4348d1SPeter Crosthwaite     qemu_fdt_setprop_phandle(fdt, pci, "interrupt-parent", mpic);
5135a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, pci, "interrupts", 24, 2);
5145a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, pci, "bus-range", 0, 255);
5153627757eSAlexander Graf     for (i = 0; i < 14; i++) {
5160dbc0798SAlexander Graf         pci_ranges[i] = cpu_to_be32(pci_ranges[i]);
5170dbc0798SAlexander Graf     }
5185a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "fsl,msi", msi_ph);
5195a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, pci, "ranges", pci_ranges, sizeof(pci_ranges));
5202eaaac1fSAlexander Graf     qemu_fdt_setprop_cells(fdt, pci, "reg",
52103f04809SIgor Mammedov                            (pmc->ccsrbar_base + MPC8544_PCI_REGS_OFFSET) >> 32,
52203f04809SIgor Mammedov                            (pmc->ccsrbar_base + MPC8544_PCI_REGS_OFFSET),
5232eaaac1fSAlexander Graf                            0, 0x1000);
5245a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "clock-frequency", 66666666);
5255a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "#interrupt-cells", 1);
5265a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "#size-cells", 2);
5275a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "#address-cells", 3);
5285a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, "/aliases", "pci0", pci);
529*2fb513d3SGreg Kurz     g_free(pci);
5300dbc0798SAlexander Graf 
53103f04809SIgor Mammedov     if (pmc->has_mpc8xxx_gpio) {
532b88e77f4SAlexander Graf         create_dt_mpc8xxx_gpio(fdt, soc, mpic);
533b88e77f4SAlexander Graf     }
534*2fb513d3SGreg Kurz     g_free(soc);
535b88e77f4SAlexander Graf 
53603f04809SIgor Mammedov     if (pmc->has_platform_bus) {
53703f04809SIgor Mammedov         platform_bus_create_devtree(pmc, fdt, mpic);
538f7087343SAlexander Graf     }
539*2fb513d3SGreg Kurz     g_free(mpic);
540f7087343SAlexander Graf 
54103f04809SIgor Mammedov     pmc->fixup_devtree(fdt);
542e6eaabebSScott Wood 
543e6eaabebSScott Wood     if (toplevel_compat) {
5445a4348d1SPeter Crosthwaite         qemu_fdt_setprop(fdt, "/", "compatible", toplevel_compat,
545e6eaabebSScott Wood                          strlen(toplevel_compat) + 1);
546e6eaabebSScott Wood     }
547e6eaabebSScott Wood 
548d1b93565SAlexander Graf done:
54928290f37SAlexander Graf     if (!dry_run) {
5505a4348d1SPeter Crosthwaite         qemu_fdt_dumpdtb(fdt, fdt_size);
55128290f37SAlexander Graf         cpu_physical_memory_write(addr, fdt, fdt_size);
552cba2026aSAlexander Graf     }
553cba2026aSAlexander Graf     ret = fdt_size;
5547ec632b4Spbrook 
5551db09b84Saurel32 out:
556347dd79dSAlexander Graf     g_free(pci_map);
5571db09b84Saurel32 
55804088adbSLiu Yu     return ret;
5591db09b84Saurel32 }
5601db09b84Saurel32 
56128290f37SAlexander Graf typedef struct DeviceTreeParams {
56203f04809SIgor Mammedov     PPCE500MachineState *machine;
56328290f37SAlexander Graf     hwaddr addr;
56428290f37SAlexander Graf     hwaddr initrd_base;
56528290f37SAlexander Graf     hwaddr initrd_size;
566903585deSAlexander Graf     hwaddr kernel_base;
567903585deSAlexander Graf     hwaddr kernel_size;
568f7087343SAlexander Graf     Notifier notifier;
56928290f37SAlexander Graf } DeviceTreeParams;
57028290f37SAlexander Graf 
57128290f37SAlexander Graf static void ppce500_reset_device_tree(void *opaque)
57228290f37SAlexander Graf {
57328290f37SAlexander Graf     DeviceTreeParams *p = opaque;
57403f04809SIgor Mammedov     ppce500_load_device_tree(p->machine, p->addr, p->initrd_base,
575903585deSAlexander Graf                              p->initrd_size, p->kernel_base, p->kernel_size,
576903585deSAlexander Graf                              false);
57728290f37SAlexander Graf }
57828290f37SAlexander Graf 
579f7087343SAlexander Graf static void ppce500_init_notify(Notifier *notifier, void *data)
580f7087343SAlexander Graf {
581f7087343SAlexander Graf     DeviceTreeParams *p = container_of(notifier, DeviceTreeParams, notifier);
582f7087343SAlexander Graf     ppce500_reset_device_tree(p);
583f7087343SAlexander Graf }
584f7087343SAlexander Graf 
58503f04809SIgor Mammedov static int ppce500_prep_device_tree(PPCE500MachineState *machine,
58628290f37SAlexander Graf                                     hwaddr addr,
58728290f37SAlexander Graf                                     hwaddr initrd_base,
588903585deSAlexander Graf                                     hwaddr initrd_size,
589903585deSAlexander Graf                                     hwaddr kernel_base,
590903585deSAlexander Graf                                     hwaddr kernel_size)
59128290f37SAlexander Graf {
59228290f37SAlexander Graf     DeviceTreeParams *p = g_new(DeviceTreeParams, 1);
5933ef96221SMarcel Apfelbaum     p->machine = machine;
59428290f37SAlexander Graf     p->addr = addr;
59528290f37SAlexander Graf     p->initrd_base = initrd_base;
59628290f37SAlexander Graf     p->initrd_size = initrd_size;
597903585deSAlexander Graf     p->kernel_base = kernel_base;
598903585deSAlexander Graf     p->kernel_size = kernel_size;
59928290f37SAlexander Graf 
60028290f37SAlexander Graf     qemu_register_reset(ppce500_reset_device_tree, p);
601f7087343SAlexander Graf     p->notifier.notify = ppce500_init_notify;
602f7087343SAlexander Graf     qemu_add_machine_init_done_notifier(&p->notifier);
60328290f37SAlexander Graf 
60428290f37SAlexander Graf     /* Issue the device tree loader once, so that we get the size of the blob */
60503f04809SIgor Mammedov     return ppce500_load_device_tree(machine, addr, initrd_base, initrd_size,
60603f04809SIgor Mammedov                                     kernel_base, kernel_size, true);
60728290f37SAlexander Graf }
60828290f37SAlexander Graf 
609cba2026aSAlexander Graf /* Create -kernel TLB entries for BookE.  */
610a36848ffSAaron Larson hwaddr booke206_page_size_to_tlb(uint64_t size)
611d1e256feSAlexander Graf {
612cba2026aSAlexander Graf     return 63 - clz64(size >> 10);
613d1e256feSAlexander Graf }
614d1e256feSAlexander Graf 
615cefd3cdbSBharat Bhushan static int booke206_initial_map_tsize(CPUPPCState *env)
6163b989d49SAlexander Graf {
617cba2026aSAlexander Graf     struct boot_info *bi = env->load_info;
618cefd3cdbSBharat Bhushan     hwaddr dt_end;
619cba2026aSAlexander Graf     int ps;
6203b989d49SAlexander Graf 
621cba2026aSAlexander Graf     /* Our initial TLB entry needs to cover everything from 0 to
622cba2026aSAlexander Graf        the device tree top */
623cba2026aSAlexander Graf     dt_end = bi->dt_base + bi->dt_size;
624cba2026aSAlexander Graf     ps = booke206_page_size_to_tlb(dt_end) + 1;
625fb37c302SAlexander Graf     if (ps & 1) {
626fb37c302SAlexander Graf         /* e500v2 can only do even TLB size bits */
627fb37c302SAlexander Graf         ps++;
628fb37c302SAlexander Graf     }
629cefd3cdbSBharat Bhushan     return ps;
630cefd3cdbSBharat Bhushan }
631cefd3cdbSBharat Bhushan 
632cefd3cdbSBharat Bhushan static uint64_t mmubooke_initial_mapsize(CPUPPCState *env)
633cefd3cdbSBharat Bhushan {
634cefd3cdbSBharat Bhushan     int tsize;
635cefd3cdbSBharat Bhushan 
636cefd3cdbSBharat Bhushan     tsize = booke206_initial_map_tsize(env);
637cefd3cdbSBharat Bhushan     return (1ULL << 10 << tsize);
638cefd3cdbSBharat Bhushan }
639cefd3cdbSBharat Bhushan 
640cefd3cdbSBharat Bhushan static void mmubooke_create_initial_mapping(CPUPPCState *env)
641cefd3cdbSBharat Bhushan {
642cefd3cdbSBharat Bhushan     ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0);
643cefd3cdbSBharat Bhushan     hwaddr size;
644cefd3cdbSBharat Bhushan     int ps;
645cefd3cdbSBharat Bhushan 
646cefd3cdbSBharat Bhushan     ps = booke206_initial_map_tsize(env);
647cba2026aSAlexander Graf     size = (ps << MAS1_TSIZE_SHIFT);
648d1e256feSAlexander Graf     tlb->mas1 = MAS1_VALID | size;
649cba2026aSAlexander Graf     tlb->mas2 = 0;
650cba2026aSAlexander Graf     tlb->mas7_3 = 0;
651d1e256feSAlexander Graf     tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
65293dd5e85SScott Wood 
65393dd5e85SScott Wood     env->tlb_dirty = true;
6543b989d49SAlexander Graf }
6553b989d49SAlexander Graf 
656b3305981SScott Wood static void ppce500_cpu_reset_sec(void *opaque)
6575c145dacSAlexander Graf {
65838f92da6SAndreas Färber     PowerPCCPU *cpu = opaque;
659259186a7SAndreas Färber     CPUState *cs = CPU(cpu);
6605c145dacSAlexander Graf 
661259186a7SAndreas Färber     cpu_reset(cs);
6625c145dacSAlexander Graf 
6635c145dacSAlexander Graf     /* Secondary CPU starts in halted state for now. Needs to change when
6645c145dacSAlexander Graf        implementing non-kernel boot. */
665259186a7SAndreas Färber     cs->halted = 1;
66627103424SAndreas Färber     cs->exception_index = EXCP_HLT;
6673b989d49SAlexander Graf }
6683b989d49SAlexander Graf 
669b3305981SScott Wood static void ppce500_cpu_reset(void *opaque)
6703b989d49SAlexander Graf {
67138f92da6SAndreas Färber     PowerPCCPU *cpu = opaque;
672259186a7SAndreas Färber     CPUState *cs = CPU(cpu);
67338f92da6SAndreas Färber     CPUPPCState *env = &cpu->env;
6743b989d49SAlexander Graf     struct boot_info *bi = env->load_info;
6753b989d49SAlexander Graf 
676259186a7SAndreas Färber     cpu_reset(cs);
6773b989d49SAlexander Graf 
6783b989d49SAlexander Graf     /* Set initial guest state. */
679259186a7SAndreas Färber     cs->halted = 0;
6803b989d49SAlexander Graf     env->gpr[1] = (16<<20) - 8;
6813b989d49SAlexander Graf     env->gpr[3] = bi->dt_base;
682cefd3cdbSBharat Bhushan     env->gpr[4] = 0;
683cefd3cdbSBharat Bhushan     env->gpr[5] = 0;
684cefd3cdbSBharat Bhushan     env->gpr[6] = EPAPR_MAGIC;
685cefd3cdbSBharat Bhushan     env->gpr[7] = mmubooke_initial_mapsize(env);
686cefd3cdbSBharat Bhushan     env->gpr[8] = 0;
687cefd3cdbSBharat Bhushan     env->gpr[9] = 0;
6883b989d49SAlexander Graf     env->nip = bi->entry;
689cba2026aSAlexander Graf     mmubooke_create_initial_mapping(env);
6903b989d49SAlexander Graf }
6913b989d49SAlexander Graf 
69203f04809SIgor Mammedov static DeviceState *ppce500_init_mpic_qemu(PPCE500MachineState *pms,
69382fc73b6SScott Wood                                            qemu_irq **irqs)
69482fc73b6SScott Wood {
69582fc73b6SScott Wood     DeviceState *dev;
69682fc73b6SScott Wood     SysBusDevice *s;
69782fc73b6SScott Wood     int i, j, k;
69803f04809SIgor Mammedov     MachineState *machine = MACHINE(pms);
69903f04809SIgor Mammedov     const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(pms);
70082fc73b6SScott Wood 
701e1766344SAndreas Färber     dev = qdev_create(NULL, TYPE_OPENPIC);
70203f04809SIgor Mammedov     object_property_add_child(OBJECT(machine), "pic", OBJECT(dev),
703e75ce32aSMichael Davidsaver                               &error_fatal);
70403f04809SIgor Mammedov     qdev_prop_set_uint32(dev, "model", pmc->mpic_version);
705d85937e6SScott Wood     qdev_prop_set_uint32(dev, "nb_cpus", smp_cpus);
706d85937e6SScott Wood 
70782fc73b6SScott Wood     qdev_init_nofail(dev);
70882fc73b6SScott Wood     s = SYS_BUS_DEVICE(dev);
70982fc73b6SScott Wood 
71082fc73b6SScott Wood     k = 0;
71182fc73b6SScott Wood     for (i = 0; i < smp_cpus; i++) {
71282fc73b6SScott Wood         for (j = 0; j < OPENPIC_OUTPUT_NB; j++) {
71382fc73b6SScott Wood             sysbus_connect_irq(s, k++, irqs[i][j]);
71482fc73b6SScott Wood         }
71582fc73b6SScott Wood     }
71682fc73b6SScott Wood 
717d85937e6SScott Wood     return dev;
718d85937e6SScott Wood }
719d85937e6SScott Wood 
72003f04809SIgor Mammedov static DeviceState *ppce500_init_mpic_kvm(const PPCE500MachineClass *pmc,
721fe656ebdSMarkus Armbruster                                           qemu_irq **irqs, Error **errp)
722d85937e6SScott Wood {
723fe656ebdSMarkus Armbruster     Error *err = NULL;
724d85937e6SScott Wood     DeviceState *dev;
725d85937e6SScott Wood     CPUState *cs;
726d85937e6SScott Wood 
727dd49c038SAndreas Färber     dev = qdev_create(NULL, TYPE_KVM_OPENPIC);
72803f04809SIgor Mammedov     qdev_prop_set_uint32(dev, "model", pmc->mpic_version);
729d85937e6SScott Wood 
730fe656ebdSMarkus Armbruster     object_property_set_bool(OBJECT(dev), true, "realized", &err);
731fe656ebdSMarkus Armbruster     if (err) {
732fe656ebdSMarkus Armbruster         error_propagate(errp, err);
733fe656ebdSMarkus Armbruster         object_unparent(OBJECT(dev));
734d85937e6SScott Wood         return NULL;
735d85937e6SScott Wood     }
736d85937e6SScott Wood 
737bdc44640SAndreas Färber     CPU_FOREACH(cs) {
738d85937e6SScott Wood         if (kvm_openpic_connect_vcpu(dev, cs)) {
739d85937e6SScott Wood             fprintf(stderr, "%s: failed to connect vcpu to irqchip\n",
740d85937e6SScott Wood                     __func__);
741d85937e6SScott Wood             abort();
742d85937e6SScott Wood         }
743d85937e6SScott Wood     }
744d85937e6SScott Wood 
745d85937e6SScott Wood     return dev;
746d85937e6SScott Wood }
747d85937e6SScott Wood 
74803f04809SIgor Mammedov static DeviceState *ppce500_init_mpic(PPCE500MachineState *pms,
749c91c187fSMichael Davidsaver                                       MemoryRegion *ccsr,
750c91c187fSMichael Davidsaver                                       qemu_irq **irqs)
751d85937e6SScott Wood {
75203f04809SIgor Mammedov     MachineState *machine = MACHINE(pms);
75303f04809SIgor Mammedov     const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(pms);
754d85937e6SScott Wood     DeviceState *dev = NULL;
755d85937e6SScott Wood     SysBusDevice *s;
756d85937e6SScott Wood 
757d85937e6SScott Wood     if (kvm_enabled()) {
758fe656ebdSMarkus Armbruster         Error *err = NULL;
759d85937e6SScott Wood 
760446f16a6SMarcel Apfelbaum         if (machine_kernel_irqchip_allowed(machine)) {
76103f04809SIgor Mammedov             dev = ppce500_init_mpic_kvm(pmc, irqs, &err);
762d85937e6SScott Wood         }
763446f16a6SMarcel Apfelbaum         if (machine_kernel_irqchip_required(machine) && !dev) {
764c29b77f9SMarkus Armbruster             error_reportf_err(err,
765c29b77f9SMarkus Armbruster                               "kernel_irqchip requested but unavailable: ");
766fe656ebdSMarkus Armbruster             exit(1);
767d85937e6SScott Wood         }
768d85937e6SScott Wood     }
769d85937e6SScott Wood 
770d85937e6SScott Wood     if (!dev) {
77103f04809SIgor Mammedov         dev = ppce500_init_mpic_qemu(pms, irqs);
772d85937e6SScott Wood     }
773d85937e6SScott Wood 
774d85937e6SScott Wood     s = SYS_BUS_DEVICE(dev);
77582fc73b6SScott Wood     memory_region_add_subregion(ccsr, MPC8544_MPIC_REGS_OFFSET,
77682fc73b6SScott Wood                                 s->mmio[0].memory);
77782fc73b6SScott Wood 
778c91c187fSMichael Davidsaver     return dev;
77982fc73b6SScott Wood }
78082fc73b6SScott Wood 
781016f7758SAlexander Graf static void ppce500_power_off(void *opaque, int line, int on)
782016f7758SAlexander Graf {
783016f7758SAlexander Graf     if (on) {
784cf83f140SEric Blake         qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
785016f7758SAlexander Graf     }
786016f7758SAlexander Graf }
787016f7758SAlexander Graf 
78803f04809SIgor Mammedov void ppce500_init(MachineState *machine)
7891db09b84Saurel32 {
79039186d8aSRichard Henderson     MemoryRegion *address_space_mem = get_system_memory();
7912646c133SAvi Kivity     MemoryRegion *ram = g_new(MemoryRegion, 1);
79203f04809SIgor Mammedov     PPCE500MachineState *pms = PPCE500_MACHINE(machine);
79303f04809SIgor Mammedov     const PPCE500MachineClass *pmc = PPCE500_MACHINE_GET_CLASS(machine);
7941db09b84Saurel32     PCIBus *pci_bus;
795e2684c0bSAndreas Färber     CPUPPCState *env = NULL;
7963812c71fSAlexander Graf     uint64_t loadaddr;
7973812c71fSAlexander Graf     hwaddr kernel_base = -1LL;
7983812c71fSAlexander Graf     int kernel_size = 0;
7993812c71fSAlexander Graf     hwaddr dt_base = 0;
8003812c71fSAlexander Graf     hwaddr initrd_base = 0;
8013812c71fSAlexander Graf     int initrd_size = 0;
8023812c71fSAlexander Graf     hwaddr cur_base = 0;
8033812c71fSAlexander Graf     char *filename;
8048d622594SDavid Engraf     const char *payload_name;
8058d622594SDavid Engraf     bool kernel_as_payload;
8063812c71fSAlexander Graf     hwaddr bios_entry = 0;
8078d622594SDavid Engraf     target_long payload_size;
8083812c71fSAlexander Graf     struct boot_info *boot_info;
8093812c71fSAlexander Graf     int dt_size;
81082fc73b6SScott Wood     int i;
811d575a6ceSBharat Bhushan     /* irq num for pin INTA, INTB, INTC and INTD is 1, 2, 3 and
812d575a6ceSBharat Bhushan      * 4 respectively */
813d575a6ceSBharat Bhushan     unsigned int pci_irq_nrs[PCI_NUM_PINS] = {1, 2, 3, 4};
814c91c187fSMichael Davidsaver     qemu_irq **irqs;
815c91c187fSMichael Davidsaver     DeviceState *dev, *mpicdev;
816e2684c0bSAndreas Färber     CPUPPCState *firstenv = NULL;
8173eddc1beSBharat Bhushan     MemoryRegion *ccsr_addr_space;
818dffb1dc2SBharat Bhushan     SysBusDevice *s;
8193eddc1beSBharat Bhushan     PPCE500CCSRState *ccsr;
8201db09b84Saurel32 
821a915249fSAlexander Graf     irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *));
822a915249fSAlexander Graf     irqs[0] = g_malloc0(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
823e61c36d5SAlexander Graf     for (i = 0; i < smp_cpus; i++) {
824397b457dSAndreas Färber         PowerPCCPU *cpu;
82555e5c285SAndreas Färber         CPUState *cs;
826e61c36d5SAlexander Graf         qemu_irq *input;
827397b457dSAndreas Färber 
82859e816fdSIgor Mammedov         cpu = POWERPC_CPU(cpu_create(machine->cpu_type));
829397b457dSAndreas Färber         env = &cpu->env;
83055e5c285SAndreas Färber         cs = CPU(cpu);
8311db09b84Saurel32 
83200469dc3SValentin Plotkin         if (env->mmu_model != POWERPC_MMU_BOOKE206) {
8336f76b817SAlistair Francis             error_report("MMU model %i not supported by this machine",
83400469dc3SValentin Plotkin                          env->mmu_model);
83500469dc3SValentin Plotkin             exit(1);
83600469dc3SValentin Plotkin         }
83700469dc3SValentin Plotkin 
838e61c36d5SAlexander Graf         if (!firstenv) {
839e61c36d5SAlexander Graf             firstenv = env;
840e61c36d5SAlexander Graf         }
841e61c36d5SAlexander Graf 
842a915249fSAlexander Graf         irqs[i] = irqs[0] + (i * OPENPIC_OUTPUT_NB);
843a915249fSAlexander Graf         input = (qemu_irq *)env->irq_inputs;
844a915249fSAlexander Graf         irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT];
845a915249fSAlexander Graf         irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT];
8466a450df9SAlexander Graf         env->spr_cb[SPR_BOOKE_PIR].default_value = cs->cpu_index = i;
84703f04809SIgor Mammedov         env->mpic_iack = pmc->ccsrbar_base + MPC8544_MPIC_REGS_OFFSET + 0xa0;
848e61c36d5SAlexander Graf 
849a34a92b9SAndreas Färber         ppc_booke_timers_init(cpu, 400000000, PPC_TIMER_E500);
8503b989d49SAlexander Graf 
8513b989d49SAlexander Graf         /* Register reset handler */
8525c145dacSAlexander Graf         if (!i) {
8535c145dacSAlexander Graf             /* Primary CPU */
8545c145dacSAlexander Graf             struct boot_info *boot_info;
855e61c36d5SAlexander Graf             boot_info = g_malloc0(sizeof(struct boot_info));
856b3305981SScott Wood             qemu_register_reset(ppce500_cpu_reset, cpu);
857e61c36d5SAlexander Graf             env->load_info = boot_info;
8585c145dacSAlexander Graf         } else {
8595c145dacSAlexander Graf             /* Secondary CPUs */
860b3305981SScott Wood             qemu_register_reset(ppce500_cpu_reset_sec, cpu);
8615c145dacSAlexander Graf         }
862e61c36d5SAlexander Graf     }
863e61c36d5SAlexander Graf 
864e61c36d5SAlexander Graf     env = firstenv;
8653b989d49SAlexander Graf 
8661db09b84Saurel32     /* Fixup Memory size on a alignment boundary */
8671db09b84Saurel32     ram_size &= ~(RAM_SIZES_ALIGN - 1);
8683ef96221SMarcel Apfelbaum     machine->ram_size = ram_size;
8691db09b84Saurel32 
8701db09b84Saurel32     /* Register Memory */
871e938ba0cSShreyas B. Prabhu     memory_region_allocate_system_memory(ram, NULL, "mpc8544ds.ram", ram_size);
8722646c133SAvi Kivity     memory_region_add_subregion(address_space_mem, 0, ram);
8731db09b84Saurel32 
8743eddc1beSBharat Bhushan     dev = qdev_create(NULL, "e500-ccsr");
8753eddc1beSBharat Bhushan     object_property_add_child(qdev_get_machine(), "e500-ccsr",
8763eddc1beSBharat Bhushan                               OBJECT(dev), NULL);
8773eddc1beSBharat Bhushan     qdev_init_nofail(dev);
8783eddc1beSBharat Bhushan     ccsr = CCSR(dev);
8793eddc1beSBharat Bhushan     ccsr_addr_space = &ccsr->ccsr_space;
88003f04809SIgor Mammedov     memory_region_add_subregion(address_space_mem, pmc->ccsrbar_base,
8813eddc1beSBharat Bhushan                                 ccsr_addr_space);
882dffb1dc2SBharat Bhushan 
88303f04809SIgor Mammedov     mpicdev = ppce500_init_mpic(pms, ccsr_addr_space, irqs);
8841db09b84Saurel32 
8851db09b84Saurel32     /* Serial */
8869bca0edbSPeter Maydell     if (serial_hd(0)) {
8873eddc1beSBharat Bhushan         serial_mm_init(ccsr_addr_space, MPC8544_SERIAL0_REGS_OFFSET,
888c91c187fSMichael Davidsaver                        0, qdev_get_gpio_in(mpicdev, 42), 399193,
8899bca0edbSPeter Maydell                        serial_hd(0), DEVICE_BIG_ENDIAN);
8902d48377aSBlue Swirl     }
8911db09b84Saurel32 
8929bca0edbSPeter Maydell     if (serial_hd(1)) {
8933eddc1beSBharat Bhushan         serial_mm_init(ccsr_addr_space, MPC8544_SERIAL1_REGS_OFFSET,
894c91c187fSMichael Davidsaver                        0, qdev_get_gpio_in(mpicdev, 42), 399193,
8959bca0edbSPeter Maydell                        serial_hd(1), DEVICE_BIG_ENDIAN);
8962d48377aSBlue Swirl     }
8971db09b84Saurel32 
898b0fb8423SAlexander Graf     /* General Utility device */
899dffb1dc2SBharat Bhushan     dev = qdev_create(NULL, "mpc8544-guts");
900dffb1dc2SBharat Bhushan     qdev_init_nofail(dev);
901dffb1dc2SBharat Bhushan     s = SYS_BUS_DEVICE(dev);
9023eddc1beSBharat Bhushan     memory_region_add_subregion(ccsr_addr_space, MPC8544_UTIL_OFFSET,
903dffb1dc2SBharat Bhushan                                 sysbus_mmio_get_region(s, 0));
904b0fb8423SAlexander Graf 
9051db09b84Saurel32     /* PCI */
906dffb1dc2SBharat Bhushan     dev = qdev_create(NULL, "e500-pcihost");
907e75ce32aSMichael Davidsaver     object_property_add_child(qdev_get_machine(), "pci-host", OBJECT(dev),
908e75ce32aSMichael Davidsaver                               &error_abort);
90903f04809SIgor Mammedov     qdev_prop_set_uint32(dev, "first_slot", pmc->pci_first_slot);
9103016dca0SBharat Bhushan     qdev_prop_set_uint32(dev, "first_pin_irq", pci_irq_nrs[0]);
911dffb1dc2SBharat Bhushan     qdev_init_nofail(dev);
912dffb1dc2SBharat Bhushan     s = SYS_BUS_DEVICE(dev);
913d575a6ceSBharat Bhushan     for (i = 0; i < PCI_NUM_PINS; i++) {
914c91c187fSMichael Davidsaver         sysbus_connect_irq(s, i, qdev_get_gpio_in(mpicdev, pci_irq_nrs[i]));
915d575a6ceSBharat Bhushan     }
916d575a6ceSBharat Bhushan 
9173eddc1beSBharat Bhushan     memory_region_add_subregion(ccsr_addr_space, MPC8544_PCI_REGS_OFFSET,
918dffb1dc2SBharat Bhushan                                 sysbus_mmio_get_region(s, 0));
919dffb1dc2SBharat Bhushan 
920d461e3b9SAlexander Graf     pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
9211db09b84Saurel32     if (!pci_bus)
9221db09b84Saurel32         printf("couldn't create PCI controller!\n");
9231db09b84Saurel32 
9241db09b84Saurel32     if (pci_bus) {
9251db09b84Saurel32         /* Register network interfaces. */
9261db09b84Saurel32         for (i = 0; i < nb_nics; i++) {
92752310c3fSPaolo Bonzini             pci_nic_init_nofail(&nd_table[i], pci_bus, "virtio-net-pci", NULL);
9281db09b84Saurel32         }
9291db09b84Saurel32     }
9301db09b84Saurel32 
9315c145dacSAlexander Graf     /* Register spinning region */
93203f04809SIgor Mammedov     sysbus_create_simple("e500-spin", pmc->spin_base, NULL);
9335c145dacSAlexander Graf 
93403f04809SIgor Mammedov     if (pmc->has_mpc8xxx_gpio) {
935016f7758SAlexander Graf         qemu_irq poweroff_irq;
936016f7758SAlexander Graf 
937b88e77f4SAlexander Graf         dev = qdev_create(NULL, "mpc8xxx_gpio");
938b88e77f4SAlexander Graf         s = SYS_BUS_DEVICE(dev);
939b88e77f4SAlexander Graf         qdev_init_nofail(dev);
940c91c187fSMichael Davidsaver         sysbus_connect_irq(s, 0, qdev_get_gpio_in(mpicdev, MPC8XXX_GPIO_IRQ));
941b88e77f4SAlexander Graf         memory_region_add_subregion(ccsr_addr_space, MPC8XXX_GPIO_OFFSET,
942b88e77f4SAlexander Graf                                     sysbus_mmio_get_region(s, 0));
943016f7758SAlexander Graf 
944016f7758SAlexander Graf         /* Power Off GPIO at Pin 0 */
945016f7758SAlexander Graf         poweroff_irq = qemu_allocate_irq(ppce500_power_off, NULL, 0);
946016f7758SAlexander Graf         qdev_connect_gpio_out(dev, 0, poweroff_irq);
947b88e77f4SAlexander Graf     }
948b88e77f4SAlexander Graf 
949f7087343SAlexander Graf     /* Platform Bus Device */
95003f04809SIgor Mammedov     if (pmc->has_platform_bus) {
951f7087343SAlexander Graf         dev = qdev_create(NULL, TYPE_PLATFORM_BUS_DEVICE);
952f7087343SAlexander Graf         dev->id = TYPE_PLATFORM_BUS_DEVICE;
95303f04809SIgor Mammedov         qdev_prop_set_uint32(dev, "num_irqs", pmc->platform_bus_num_irqs);
95403f04809SIgor Mammedov         qdev_prop_set_uint32(dev, "mmio_size", pmc->platform_bus_size);
955f7087343SAlexander Graf         qdev_init_nofail(dev);
956f7087343SAlexander Graf         s = SYS_BUS_DEVICE(dev);
957f7087343SAlexander Graf 
95803f04809SIgor Mammedov         for (i = 0; i < pmc->platform_bus_num_irqs; i++) {
95903f04809SIgor Mammedov             int irqn = pmc->platform_bus_first_irq + i;
960c91c187fSMichael Davidsaver             sysbus_connect_irq(s, i, qdev_get_gpio_in(mpicdev, irqn));
961f7087343SAlexander Graf         }
962f7087343SAlexander Graf 
963f7087343SAlexander Graf         memory_region_add_subregion(address_space_mem,
96403f04809SIgor Mammedov                                     pmc->platform_bus_base,
965f7087343SAlexander Graf                                     sysbus_mmio_get_region(s, 0));
966f7087343SAlexander Graf     }
967f7087343SAlexander Graf 
9688d622594SDavid Engraf     /*
9698d622594SDavid Engraf      * Smart firmware defaults ahead!
9708d622594SDavid Engraf      *
9718d622594SDavid Engraf      * We follow the following table to select which payload we execute.
9728d622594SDavid Engraf      *
9738d622594SDavid Engraf      *  -kernel | -bios | payload
9748d622594SDavid Engraf      * ---------+-------+---------
9758d622594SDavid Engraf      *     N    |   Y   | u-boot
9768d622594SDavid Engraf      *     N    |   N   | u-boot
9778d622594SDavid Engraf      *     Y    |   Y   | u-boot
9788d622594SDavid Engraf      *     Y    |   N   | kernel
9798d622594SDavid Engraf      *
9808d622594SDavid Engraf      * This ensures backwards compatibility with how we used to expose
9818d622594SDavid Engraf      * -kernel to users but allows them to run through u-boot as well.
9828d622594SDavid Engraf      */
9838d622594SDavid Engraf     kernel_as_payload = false;
9848d622594SDavid Engraf     if (bios_name == NULL) {
9853ef96221SMarcel Apfelbaum         if (machine->kernel_filename) {
9868d622594SDavid Engraf             payload_name = machine->kernel_filename;
9878d622594SDavid Engraf             kernel_as_payload = true;
9888d622594SDavid Engraf         } else {
9898d622594SDavid Engraf             payload_name = "u-boot.e500";
9908d622594SDavid Engraf         }
9918d622594SDavid Engraf     } else {
9928d622594SDavid Engraf         payload_name = bios_name;
9938d622594SDavid Engraf     }
9948d622594SDavid Engraf 
9958d622594SDavid Engraf     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, payload_name);
9968d622594SDavid Engraf 
9978d622594SDavid Engraf     payload_size = load_elf(filename, NULL, NULL, &bios_entry, &loadaddr, NULL,
9988d622594SDavid Engraf                             1, PPC_ELF_MACHINE, 0, 0);
9998d622594SDavid Engraf     if (payload_size < 0) {
10008d622594SDavid Engraf         /*
10018d622594SDavid Engraf          * Hrm. No ELF image? Try a uImage, maybe someone is giving us an
10028d622594SDavid Engraf          * ePAPR compliant kernel
10038d622594SDavid Engraf          */
10048d622594SDavid Engraf         payload_size = load_uimage(filename, &bios_entry, &loadaddr, NULL,
10058d622594SDavid Engraf                                    NULL, NULL);
10068d622594SDavid Engraf         if (payload_size < 0) {
10078d622594SDavid Engraf             error_report("qemu: could not load firmware '%s'", filename);
10088d622594SDavid Engraf             exit(1);
10098d622594SDavid Engraf         }
10108d622594SDavid Engraf     }
10118d622594SDavid Engraf 
10128d622594SDavid Engraf     g_free(filename);
10138d622594SDavid Engraf 
10148d622594SDavid Engraf     if (kernel_as_payload) {
10158d622594SDavid Engraf         kernel_base = loadaddr;
10168d622594SDavid Engraf         kernel_size = payload_size;
10178d622594SDavid Engraf     }
10188d622594SDavid Engraf 
10198d622594SDavid Engraf     cur_base = loadaddr + payload_size;
1020b4a5f24aSDavid Engraf     if (cur_base < (32 * 1024 * 1024)) {
1021b4a5f24aSDavid Engraf         /* u-boot occupies memory up to 32MB, so load blobs above */
1022b4a5f24aSDavid Engraf         cur_base = (32 * 1024 * 1024);
1023b4a5f24aSDavid Engraf     }
10248d622594SDavid Engraf 
10258d622594SDavid Engraf     /* Load bare kernel only if no bios/u-boot has been provided */
10268d622594SDavid Engraf     if (machine->kernel_filename && !kernel_as_payload) {
10273812c71fSAlexander Graf         kernel_base = cur_base;
10283812c71fSAlexander Graf         kernel_size = load_image_targphys(machine->kernel_filename,
10293812c71fSAlexander Graf                                           cur_base,
10303812c71fSAlexander Graf                                           ram_size - cur_base);
10311db09b84Saurel32         if (kernel_size < 0) {
10326f76b817SAlistair Francis             error_report("could not load kernel '%s'",
10333ef96221SMarcel Apfelbaum                          machine->kernel_filename);
10341db09b84Saurel32             exit(1);
10351db09b84Saurel32         }
1036528e536eSAlexander Graf 
10373812c71fSAlexander Graf         cur_base += kernel_size;
10381db09b84Saurel32     }
10391db09b84Saurel32 
10401db09b84Saurel32     /* Load initrd. */
10413ef96221SMarcel Apfelbaum     if (machine->initrd_filename) {
1042528e536eSAlexander Graf         initrd_base = (cur_base + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK;
10433ef96221SMarcel Apfelbaum         initrd_size = load_image_targphys(machine->initrd_filename, initrd_base,
1044d7585251Spbrook                                           ram_size - initrd_base);
10451db09b84Saurel32 
10461db09b84Saurel32         if (initrd_size < 0) {
10476f76b817SAlistair Francis             error_report("could not load initial ram disk '%s'",
10483ef96221SMarcel Apfelbaum                          machine->initrd_filename);
10491db09b84Saurel32             exit(1);
10501db09b84Saurel32         }
1051528e536eSAlexander Graf 
1052528e536eSAlexander Graf         cur_base = initrd_base + initrd_size;
10531db09b84Saurel32     }
10541db09b84Saurel32 
10553812c71fSAlexander Graf     /*
10568d622594SDavid Engraf      * Reserve space for dtb behind the kernel image because Linux has a bug
10578d622594SDavid Engraf      * where it can only handle the dtb if it's within the first 64MB of where
10588d622594SDavid Engraf      * <kernel> starts. dtb cannot not reach initrd_base because INITRD_LOAD_PAD
10598d622594SDavid Engraf      * ensures enough space between kernel and initrd.
10603812c71fSAlexander Graf      */
10618d622594SDavid Engraf     dt_base = (loadaddr + payload_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
10628d622594SDavid Engraf     if (dt_base + DTB_MAX_SIZE > ram_size) {
10638d622594SDavid Engraf             error_report("qemu: not enough memory for device tree");
10643812c71fSAlexander Graf             exit(1);
10653812c71fSAlexander Graf     }
10665c145dacSAlexander Graf 
106703f04809SIgor Mammedov     dt_size = ppce500_prep_device_tree(pms, dt_base,
1068903585deSAlexander Graf                                        initrd_base, initrd_size,
10693812c71fSAlexander Graf                                        kernel_base, kernel_size);
1070cba2026aSAlexander Graf     if (dt_size < 0) {
10716f76b817SAlistair Francis         error_report("couldn't load device tree");
10721db09b84Saurel32         exit(1);
10731db09b84Saurel32     }
1074b8dec144SAlexander Graf     assert(dt_size < DTB_MAX_SIZE);
10751db09b84Saurel32 
1076e61c36d5SAlexander Graf     boot_info = env->load_info;
10773812c71fSAlexander Graf     boot_info->entry = bios_entry;
10783b989d49SAlexander Graf     boot_info->dt_base = dt_base;
1079cba2026aSAlexander Graf     boot_info->dt_size = dt_size;
10801db09b84Saurel32 }
10813eddc1beSBharat Bhushan 
1082d0c2b0d0Sxiaoqiang zhao static void e500_ccsr_initfn(Object *obj)
10833eddc1beSBharat Bhushan {
1084d0c2b0d0Sxiaoqiang zhao     PPCE500CCSRState *ccsr = CCSR(obj);
1085d0c2b0d0Sxiaoqiang zhao     memory_region_init(&ccsr->ccsr_space, obj, "e500-ccsr",
10863eddc1beSBharat Bhushan                        MPC8544_CCSRBAR_SIZE);
10873eddc1beSBharat Bhushan }
10883eddc1beSBharat Bhushan 
10893eddc1beSBharat Bhushan static const TypeInfo e500_ccsr_info = {
10903eddc1beSBharat Bhushan     .name          = TYPE_CCSR,
10913eddc1beSBharat Bhushan     .parent        = TYPE_SYS_BUS_DEVICE,
10923eddc1beSBharat Bhushan     .instance_size = sizeof(PPCE500CCSRState),
1093d0c2b0d0Sxiaoqiang zhao     .instance_init = e500_ccsr_initfn,
10943eddc1beSBharat Bhushan };
10953eddc1beSBharat Bhushan 
109603f04809SIgor Mammedov static const TypeInfo ppce500_info = {
109703f04809SIgor Mammedov     .name          = TYPE_PPCE500_MACHINE,
109803f04809SIgor Mammedov     .parent        = TYPE_MACHINE,
109903f04809SIgor Mammedov     .abstract      = true,
110003f04809SIgor Mammedov     .class_size    = sizeof(PPCE500MachineClass),
110103f04809SIgor Mammedov };
110203f04809SIgor Mammedov 
11033eddc1beSBharat Bhushan static void e500_register_types(void)
11043eddc1beSBharat Bhushan {
11053eddc1beSBharat Bhushan     type_register_static(&e500_ccsr_info);
110603f04809SIgor Mammedov     type_register_static(&ppce500_info);
11073eddc1beSBharat Bhushan }
11083eddc1beSBharat Bhushan 
11093eddc1beSBharat Bhushan type_init(e500_register_types)
1110