xref: /qemu/hw/ppc/e500.c (revision cf83f140059f21d4629ae4b61d468c3baef2bb4c)
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"
191db09b84Saurel32 #include "qemu-common.h"
20e6eaabebSScott Wood #include "e500.h"
213eddc1beSBharat Bhushan #include "e500-ccsr.h"
221422e32dSPaolo Bonzini #include "net/net.h"
231de7afc9SPaolo Bonzini #include "qemu/config-file.h"
244a18e7c9SScott Wood #include "hw/hw.h"
250d09e41aSPaolo Bonzini #include "hw/char/serial.h"
26a2cb15b0SMichael S. Tsirkin #include "hw/pci/pci.h"
274a18e7c9SScott Wood #include "hw/boards.h"
289c17d615SPaolo Bonzini #include "sysemu/sysemu.h"
299c17d615SPaolo Bonzini #include "sysemu/kvm.h"
301db09b84Saurel32 #include "kvm_ppc.h"
319c17d615SPaolo Bonzini #include "sysemu/device_tree.h"
320d09e41aSPaolo Bonzini #include "hw/ppc/openpic.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"
390d09e41aSPaolo Bonzini #include "hw/pci-host/ppce500.h"
40f7087343SAlexander Graf #include "qemu/error-report.h"
41f7087343SAlexander Graf #include "hw/platform-bus.h"
42fdfb7f2cSAlexander Graf #include "hw/net/fsl_etsec/etsec.h"
431db09b84Saurel32 
44cefd3cdbSBharat Bhushan #define EPAPR_MAGIC                (0x45504150)
451db09b84Saurel32 #define BINARY_DEVICE_TREE_FILE    "mpc8544ds.dtb"
469dd5eba1SScott Wood #define DTC_LOAD_PAD               0x1800000
4775bb6589SLiu Yu #define DTC_PAD_MASK               0xFFFFF
48b8dec144SAlexander Graf #define DTB_MAX_SIZE               (8 * 1024 * 1024)
4975bb6589SLiu Yu #define INITRD_LOAD_PAD            0x2000000
5075bb6589SLiu Yu #define INITRD_PAD_MASK            0xFFFFFF
511db09b84Saurel32 
521db09b84Saurel32 #define RAM_SIZES_ALIGN            (64UL << 20)
531db09b84Saurel32 
54b3305981SScott Wood /* TODO: parameterize */
55ed2bc496SAlexander Graf #define MPC8544_CCSRBAR_SIZE       0x00100000ULL
56dffb1dc2SBharat Bhushan #define MPC8544_MPIC_REGS_OFFSET   0x40000ULL
57a911b7a9SAlexander Graf #define MPC8544_MSI_REGS_OFFSET   0x41600ULL
58dffb1dc2SBharat Bhushan #define MPC8544_SERIAL0_REGS_OFFSET 0x4500ULL
59dffb1dc2SBharat Bhushan #define MPC8544_SERIAL1_REGS_OFFSET 0x4600ULL
60dffb1dc2SBharat Bhushan #define MPC8544_PCI_REGS_OFFSET    0x8000ULL
61ed2bc496SAlexander Graf #define MPC8544_PCI_REGS_SIZE      0x1000ULL
62dffb1dc2SBharat Bhushan #define MPC8544_UTIL_OFFSET        0xe0000ULL
63b88e77f4SAlexander Graf #define MPC8XXX_GPIO_OFFSET        0x000FF000ULL
6482e345f5SAmit Tomar #define MPC8XXX_GPIO_IRQ           47
651db09b84Saurel32 
663b989d49SAlexander Graf struct boot_info
673b989d49SAlexander Graf {
683b989d49SAlexander Graf     uint32_t dt_base;
69cba2026aSAlexander Graf     uint32_t dt_size;
703b989d49SAlexander Graf     uint32_t entry;
713b989d49SAlexander Graf };
723b989d49SAlexander Graf 
73347dd79dSAlexander Graf static uint32_t *pci_map_create(void *fdt, uint32_t mpic, int first_slot,
74347dd79dSAlexander Graf                                 int nr_slots, int *len)
750dbc0798SAlexander Graf {
76347dd79dSAlexander Graf     int i = 0;
77347dd79dSAlexander Graf     int slot;
78347dd79dSAlexander Graf     int pci_irq;
799e2c1298SAlexander Graf     int host_irq;
80347dd79dSAlexander Graf     int last_slot = first_slot + nr_slots;
81347dd79dSAlexander Graf     uint32_t *pci_map;
820dbc0798SAlexander Graf 
83347dd79dSAlexander Graf     *len = nr_slots * 4 * 7 * sizeof(uint32_t);
84347dd79dSAlexander Graf     pci_map = g_malloc(*len);
85347dd79dSAlexander Graf 
86347dd79dSAlexander Graf     for (slot = first_slot; slot < last_slot; slot++) {
87347dd79dSAlexander Graf         for (pci_irq = 0; pci_irq < 4; pci_irq++) {
88347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(slot << 11);
89347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(0x0);
90347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(0x0);
91347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(pci_irq + 1);
92347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(mpic);
939e2c1298SAlexander Graf             host_irq = ppce500_pci_map_irq_slot(slot, pci_irq);
949e2c1298SAlexander Graf             pci_map[i++] = cpu_to_be32(host_irq + 1);
95347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(0x1);
960dbc0798SAlexander Graf         }
970dbc0798SAlexander Graf     }
980dbc0798SAlexander Graf 
99347dd79dSAlexander Graf     assert((i * sizeof(uint32_t)) == *len);
100347dd79dSAlexander Graf 
101347dd79dSAlexander Graf     return pci_map;
102347dd79dSAlexander Graf }
103347dd79dSAlexander Graf 
104a053a7ceSAlexander Graf static void dt_serial_create(void *fdt, unsigned long long offset,
105a053a7ceSAlexander Graf                              const char *soc, const char *mpic,
106a053a7ceSAlexander Graf                              const char *alias, int idx, bool defcon)
107a053a7ceSAlexander Graf {
108a053a7ceSAlexander Graf     char ser[128];
109a053a7ceSAlexander Graf 
110a053a7ceSAlexander Graf     snprintf(ser, sizeof(ser), "%s/serial@%llx", soc, offset);
1115a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, ser);
1125a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, ser, "device_type", "serial");
1135a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, ser, "compatible", "ns16550");
1145a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, ser, "reg", offset, 0x100);
1155a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, ser, "cell-index", idx);
1165a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, ser, "clock-frequency", 0);
1175a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, ser, "interrupts", 42, 2);
1185a4348d1SPeter Crosthwaite     qemu_fdt_setprop_phandle(fdt, ser, "interrupt-parent", mpic);
1195a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, "/aliases", alias, ser);
120a053a7ceSAlexander Graf 
121a053a7ceSAlexander Graf     if (defcon) {
1225a4348d1SPeter Crosthwaite         qemu_fdt_setprop_string(fdt, "/chosen", "linux,stdout-path", ser);
123a053a7ceSAlexander Graf     }
124a053a7ceSAlexander Graf }
125a053a7ceSAlexander Graf 
126b88e77f4SAlexander Graf static void create_dt_mpc8xxx_gpio(void *fdt, const char *soc, const char *mpic)
127b88e77f4SAlexander Graf {
128b88e77f4SAlexander Graf     hwaddr mmio0 = MPC8XXX_GPIO_OFFSET;
129b88e77f4SAlexander Graf     int irq0 = MPC8XXX_GPIO_IRQ;
130b88e77f4SAlexander Graf     gchar *node = g_strdup_printf("%s/gpio@%"PRIx64, soc, mmio0);
131016f7758SAlexander Graf     gchar *poweroff = g_strdup_printf("%s/power-off", soc);
132016f7758SAlexander Graf     int gpio_ph;
133b88e77f4SAlexander Graf 
134b88e77f4SAlexander Graf     qemu_fdt_add_subnode(fdt, node);
135b88e77f4SAlexander Graf     qemu_fdt_setprop_string(fdt, node, "compatible", "fsl,qoriq-gpio");
136b88e77f4SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "reg", mmio0, 0x1000);
137b88e77f4SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "interrupts", irq0, 0x2);
138b88e77f4SAlexander Graf     qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", mpic);
139b88e77f4SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "#gpio-cells", 2);
140b88e77f4SAlexander Graf     qemu_fdt_setprop(fdt, node, "gpio-controller", NULL, 0);
141016f7758SAlexander Graf     gpio_ph = qemu_fdt_alloc_phandle(fdt);
142016f7758SAlexander Graf     qemu_fdt_setprop_cell(fdt, node, "phandle", gpio_ph);
143016f7758SAlexander Graf     qemu_fdt_setprop_cell(fdt, node, "linux,phandle", gpio_ph);
144016f7758SAlexander Graf 
145016f7758SAlexander Graf     /* Power Off Pin */
146016f7758SAlexander Graf     qemu_fdt_add_subnode(fdt, poweroff);
147016f7758SAlexander Graf     qemu_fdt_setprop_string(fdt, poweroff, "compatible", "gpio-poweroff");
148016f7758SAlexander Graf     qemu_fdt_setprop_cells(fdt, poweroff, "gpios", gpio_ph, 0, 0);
149b88e77f4SAlexander Graf 
150b88e77f4SAlexander Graf     g_free(node);
151016f7758SAlexander Graf     g_free(poweroff);
152b88e77f4SAlexander Graf }
153b88e77f4SAlexander Graf 
154f7087343SAlexander Graf typedef struct PlatformDevtreeData {
155f7087343SAlexander Graf     void *fdt;
156f7087343SAlexander Graf     const char *mpic;
157f7087343SAlexander Graf     int irq_start;
158f7087343SAlexander Graf     const char *node;
159f7087343SAlexander Graf     PlatformBusDevice *pbus;
160f7087343SAlexander Graf } PlatformDevtreeData;
161f7087343SAlexander Graf 
162fdfb7f2cSAlexander Graf static int create_devtree_etsec(SysBusDevice *sbdev, PlatformDevtreeData *data)
163fdfb7f2cSAlexander Graf {
164fdfb7f2cSAlexander Graf     eTSEC *etsec = ETSEC_COMMON(sbdev);
165fdfb7f2cSAlexander Graf     PlatformBusDevice *pbus = data->pbus;
166fdfb7f2cSAlexander Graf     hwaddr mmio0 = platform_bus_get_mmio_addr(pbus, sbdev, 0);
167fdfb7f2cSAlexander Graf     int irq0 = platform_bus_get_irqn(pbus, sbdev, 0);
168fdfb7f2cSAlexander Graf     int irq1 = platform_bus_get_irqn(pbus, sbdev, 1);
169fdfb7f2cSAlexander Graf     int irq2 = platform_bus_get_irqn(pbus, sbdev, 2);
170fdfb7f2cSAlexander Graf     gchar *node = g_strdup_printf("/platform/ethernet@%"PRIx64, mmio0);
171fdfb7f2cSAlexander Graf     gchar *group = g_strdup_printf("%s/queue-group", node);
172fdfb7f2cSAlexander Graf     void *fdt = data->fdt;
173fdfb7f2cSAlexander Graf 
174fdfb7f2cSAlexander Graf     assert((int64_t)mmio0 >= 0);
175fdfb7f2cSAlexander Graf     assert(irq0 >= 0);
176fdfb7f2cSAlexander Graf     assert(irq1 >= 0);
177fdfb7f2cSAlexander Graf     assert(irq2 >= 0);
178fdfb7f2cSAlexander Graf 
179fdfb7f2cSAlexander Graf     qemu_fdt_add_subnode(fdt, node);
180fdfb7f2cSAlexander Graf     qemu_fdt_setprop_string(fdt, node, "device_type", "network");
181fdfb7f2cSAlexander Graf     qemu_fdt_setprop_string(fdt, node, "compatible", "fsl,etsec2");
182fdfb7f2cSAlexander Graf     qemu_fdt_setprop_string(fdt, node, "model", "eTSEC");
183fdfb7f2cSAlexander Graf     qemu_fdt_setprop(fdt, node, "local-mac-address", etsec->conf.macaddr.a, 6);
184fdfb7f2cSAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "fixed-link", 0, 1, 1000, 0, 0);
185fdfb7f2cSAlexander Graf 
186fdfb7f2cSAlexander Graf     qemu_fdt_add_subnode(fdt, group);
187fdfb7f2cSAlexander Graf     qemu_fdt_setprop_cells(fdt, group, "reg", mmio0, 0x1000);
188fdfb7f2cSAlexander Graf     qemu_fdt_setprop_cells(fdt, group, "interrupts",
189fdfb7f2cSAlexander Graf         data->irq_start + irq0, 0x2,
190fdfb7f2cSAlexander Graf         data->irq_start + irq1, 0x2,
191fdfb7f2cSAlexander Graf         data->irq_start + irq2, 0x2);
192fdfb7f2cSAlexander Graf 
193fdfb7f2cSAlexander Graf     g_free(node);
194fdfb7f2cSAlexander Graf     g_free(group);
195fdfb7f2cSAlexander Graf 
196fdfb7f2cSAlexander Graf     return 0;
197fdfb7f2cSAlexander Graf }
198fdfb7f2cSAlexander Graf 
1994f01a637SDavid Gibson static void sysbus_device_create_devtree(SysBusDevice *sbdev, void *opaque)
200f7087343SAlexander Graf {
201f7087343SAlexander Graf     PlatformDevtreeData *data = opaque;
202f7087343SAlexander Graf     bool matched = false;
203f7087343SAlexander Graf 
204fdfb7f2cSAlexander Graf     if (object_dynamic_cast(OBJECT(sbdev), TYPE_ETSEC_COMMON)) {
205fdfb7f2cSAlexander Graf         create_devtree_etsec(sbdev, data);
206fdfb7f2cSAlexander Graf         matched = true;
207fdfb7f2cSAlexander Graf     }
208fdfb7f2cSAlexander Graf 
209f7087343SAlexander Graf     if (!matched) {
210f7087343SAlexander Graf         error_report("Device %s is not supported by this machine yet.",
211f7087343SAlexander Graf                      qdev_fw_name(DEVICE(sbdev)));
212f7087343SAlexander Graf         exit(1);
213f7087343SAlexander Graf     }
214f7087343SAlexander Graf }
215f7087343SAlexander Graf 
216f7087343SAlexander Graf static void platform_bus_create_devtree(PPCE500Params *params, void *fdt,
217f7087343SAlexander Graf                                         const char *mpic)
218f7087343SAlexander Graf {
219f7087343SAlexander Graf     gchar *node = g_strdup_printf("/platform@%"PRIx64, params->platform_bus_base);
220f7087343SAlexander Graf     const char platcomp[] = "qemu,platform\0simple-bus";
221f7087343SAlexander Graf     uint64_t addr = params->platform_bus_base;
222f7087343SAlexander Graf     uint64_t size = params->platform_bus_size;
223f7087343SAlexander Graf     int irq_start = params->platform_bus_first_irq;
224f7087343SAlexander Graf     PlatformBusDevice *pbus;
225f7087343SAlexander Graf     DeviceState *dev;
226f7087343SAlexander Graf 
227f7087343SAlexander Graf     /* Create a /platform node that we can put all devices into */
228f7087343SAlexander Graf 
229f7087343SAlexander Graf     qemu_fdt_add_subnode(fdt, node);
230f7087343SAlexander Graf     qemu_fdt_setprop(fdt, node, "compatible", platcomp, sizeof(platcomp));
231f7087343SAlexander Graf 
232f7087343SAlexander Graf     /* Our platform bus region is less than 32bit big, so 1 cell is enough for
233f7087343SAlexander Graf        address and size */
234f7087343SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "#size-cells", 1);
235f7087343SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "#address-cells", 1);
236f7087343SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "ranges", 0, addr >> 32, addr, size);
237f7087343SAlexander Graf 
238f7087343SAlexander Graf     qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", mpic);
239f7087343SAlexander Graf 
240f7087343SAlexander Graf     dev = qdev_find_recursive(sysbus_get_default(), TYPE_PLATFORM_BUS_DEVICE);
241f7087343SAlexander Graf     pbus = PLATFORM_BUS_DEVICE(dev);
242f7087343SAlexander Graf 
243f7087343SAlexander Graf     /* We can only create dt nodes for dynamic devices when they're ready */
244f7087343SAlexander Graf     if (pbus->done_gathering) {
245f7087343SAlexander Graf         PlatformDevtreeData data = {
246f7087343SAlexander Graf             .fdt = fdt,
247f7087343SAlexander Graf             .mpic = mpic,
248f7087343SAlexander Graf             .irq_start = irq_start,
249f7087343SAlexander Graf             .node = node,
250f7087343SAlexander Graf             .pbus = pbus,
251f7087343SAlexander Graf         };
252f7087343SAlexander Graf 
253f7087343SAlexander Graf         /* Loop through all dynamic sysbus devices and create nodes for them */
254f7087343SAlexander Graf         foreach_dynamic_sysbus_device(sysbus_device_create_devtree, &data);
255f7087343SAlexander Graf     }
256f7087343SAlexander Graf 
257f7087343SAlexander Graf     g_free(node);
258f7087343SAlexander Graf }
259f7087343SAlexander Graf 
2603ef96221SMarcel Apfelbaum static int ppce500_load_device_tree(MachineState *machine,
261e6eaabebSScott Wood                                     PPCE500Params *params,
262a8170e5eSAvi Kivity                                     hwaddr addr,
263a8170e5eSAvi Kivity                                     hwaddr initrd_base,
26428290f37SAlexander Graf                                     hwaddr initrd_size,
265903585deSAlexander Graf                                     hwaddr kernel_base,
266903585deSAlexander Graf                                     hwaddr kernel_size,
26728290f37SAlexander Graf                                     bool dry_run)
2681db09b84Saurel32 {
26928290f37SAlexander Graf     CPUPPCState *env = first_cpu->env_ptr;
270dbf916d8SAurelien Jarno     int ret = -1;
2713ef96221SMarcel Apfelbaum     uint64_t mem_reg_property[] = { 0, cpu_to_be64(machine->ram_size) };
2727ec632b4Spbrook     int fdt_size;
273dbf916d8SAurelien Jarno     void *fdt;
2745de6b46dSAlexander Graf     uint8_t hypercall[16];
275911d6e7aSAlexander Graf     uint32_t clock_freq = 400000000;
276911d6e7aSAlexander Graf     uint32_t tb_freq = 400000000;
277621d05e3SAlexander Graf     int i;
278ebb9518aSAlexander Graf     char compatible_sb[] = "fsl,mpc8544-immr\0simple-bus";
2795da96624SAlexander Graf     char soc[128];
28019ac9deaSAlexander Graf     char mpic[128];
28119ac9deaSAlexander Graf     uint32_t mpic_ph;
282a911b7a9SAlexander Graf     uint32_t msi_ph;
283f5038483SAlexander Graf     char gutil[128];
2840dbc0798SAlexander Graf     char pci[128];
285a911b7a9SAlexander Graf     char msi[128];
286347dd79dSAlexander Graf     uint32_t *pci_map = NULL;
287347dd79dSAlexander Graf     int len;
2883627757eSAlexander Graf     uint32_t pci_ranges[14] =
2893627757eSAlexander Graf         {
290cb3778a0SAlexander Graf             0x2000000, 0x0, params->pci_mmio_bus_base,
291cb3778a0SAlexander Graf             params->pci_mmio_base >> 32, params->pci_mmio_base,
2923627757eSAlexander Graf             0x0, 0x20000000,
2933627757eSAlexander Graf 
2943627757eSAlexander Graf             0x1000000, 0x0, 0x0,
2952eaaac1fSAlexander Graf             params->pci_pio_base >> 32, params->pci_pio_base,
2963627757eSAlexander Graf             0x0, 0x10000,
2973627757eSAlexander Graf         };
2982ff3de68SMarkus Armbruster     QemuOpts *machine_opts = qemu_get_machine_opts();
2992ff3de68SMarkus Armbruster     const char *dtb_file = qemu_opt_get(machine_opts, "dtb");
3002ff3de68SMarkus Armbruster     const char *toplevel_compat = qemu_opt_get(machine_opts, "dt_compatible");
301d1b93565SAlexander Graf 
302d1b93565SAlexander Graf     if (dtb_file) {
303d1b93565SAlexander Graf         char *filename;
304d1b93565SAlexander Graf         filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_file);
305d1b93565SAlexander Graf         if (!filename) {
306d1b93565SAlexander Graf             goto out;
307d1b93565SAlexander Graf         }
308d1b93565SAlexander Graf 
309d1b93565SAlexander Graf         fdt = load_device_tree(filename, &fdt_size);
3102343dd11SMichael Tokarev         g_free(filename);
311d1b93565SAlexander Graf         if (!fdt) {
312d1b93565SAlexander Graf             goto out;
313d1b93565SAlexander Graf         }
314d1b93565SAlexander Graf         goto done;
315d1b93565SAlexander Graf     }
3161db09b84Saurel32 
3172636fcb6SAlexander Graf     fdt = create_device_tree(&fdt_size);
3185cea8590SPaul Brook     if (fdt == NULL) {
3195cea8590SPaul Brook         goto out;
3205cea8590SPaul Brook     }
3211db09b84Saurel32 
3221db09b84Saurel32     /* Manipulate device tree in memory. */
3235a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 2);
3245a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 2);
32551b852b7SAlexander Graf 
3265a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, "/memory");
3275a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, "/memory", "device_type", "memory");
3285a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, "/memory", "reg", mem_reg_property,
3291db09b84Saurel32                      sizeof(mem_reg_property));
3301db09b84Saurel32 
3315a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, "/chosen");
3323b989d49SAlexander Graf     if (initrd_size) {
3335a4348d1SPeter Crosthwaite         ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start",
3341db09b84Saurel32                                     initrd_base);
3353b989d49SAlexander Graf         if (ret < 0) {
3361db09b84Saurel32             fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
3373b989d49SAlexander Graf         }
3381db09b84Saurel32 
3395a4348d1SPeter Crosthwaite         ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
3401db09b84Saurel32                                     (initrd_base + initrd_size));
3413b989d49SAlexander Graf         if (ret < 0) {
3421db09b84Saurel32             fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
3433b989d49SAlexander Graf         }
344903585deSAlexander Graf 
345903585deSAlexander Graf     }
346903585deSAlexander Graf 
347903585deSAlexander Graf     if (kernel_base != -1ULL) {
348903585deSAlexander Graf         qemu_fdt_setprop_cells(fdt, "/chosen", "qemu,boot-kernel",
349903585deSAlexander Graf                                      kernel_base >> 32, kernel_base,
350903585deSAlexander Graf                                      kernel_size >> 32, kernel_size);
3513b989d49SAlexander Graf     }
3521db09b84Saurel32 
3535a4348d1SPeter Crosthwaite     ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
3543ef96221SMarcel Apfelbaum                                       machine->kernel_cmdline);
3551db09b84Saurel32     if (ret < 0)
3561db09b84Saurel32         fprintf(stderr, "couldn't set /chosen/bootargs\n");
3571db09b84Saurel32 
3581db09b84Saurel32     if (kvm_enabled()) {
359911d6e7aSAlexander Graf         /* Read out host's frequencies */
360911d6e7aSAlexander Graf         clock_freq = kvmppc_get_clockfreq();
361911d6e7aSAlexander Graf         tb_freq = kvmppc_get_tbfreq();
3625de6b46dSAlexander Graf 
3635de6b46dSAlexander Graf         /* indicate KVM hypercall interface */
3645a4348d1SPeter Crosthwaite         qemu_fdt_add_subnode(fdt, "/hypervisor");
3655a4348d1SPeter Crosthwaite         qemu_fdt_setprop_string(fdt, "/hypervisor", "compatible",
3665de6b46dSAlexander Graf                                 "linux,kvm");
3675de6b46dSAlexander Graf         kvmppc_get_hypercall(env, hypercall, sizeof(hypercall));
3685a4348d1SPeter Crosthwaite         qemu_fdt_setprop(fdt, "/hypervisor", "hcall-instructions",
3695de6b46dSAlexander Graf                          hypercall, sizeof(hypercall));
3701a61a9aeSStuart Yoder         /* if KVM supports the idle hcall, set property indicating this */
3711a61a9aeSStuart Yoder         if (kvmppc_get_hasidle(env)) {
3725a4348d1SPeter Crosthwaite             qemu_fdt_setprop(fdt, "/hypervisor", "has-idle", NULL, 0);
3731a61a9aeSStuart Yoder         }
3741db09b84Saurel32     }
3751db09b84Saurel32 
376625e665bSAlexander Graf     /* Create CPU nodes */
3775a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, "/cpus");
3785a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 1);
3795a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0);
380625e665bSAlexander Graf 
3811e3debf0SAlexander Graf     /* We need to generate the cpu nodes in reverse order, so Linux can pick
3821e3debf0SAlexander Graf        the first node as boot node and be happy */
3831e3debf0SAlexander Graf     for (i = smp_cpus - 1; i >= 0; i--) {
384440c8152SAndreas Färber         CPUState *cpu;
3850f20ba62SAlexey Kardashevskiy         PowerPCCPU *pcpu;
386621d05e3SAlexander Graf         char cpu_name[128];
3872eaaac1fSAlexander Graf         uint64_t cpu_release_addr = params->spin_base + (i * 0x20);
38810f25a46SAlexander Graf 
389440c8152SAndreas Färber         cpu = qemu_get_cpu(i);
39055e5c285SAndreas Färber         if (cpu == NULL) {
3911e3debf0SAlexander Graf             continue;
3921e3debf0SAlexander Graf         }
393440c8152SAndreas Färber         env = cpu->env_ptr;
3940f20ba62SAlexey Kardashevskiy         pcpu = POWERPC_CPU(cpu);
3951e3debf0SAlexander Graf 
39655e5c285SAndreas Färber         snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x",
3970f20ba62SAlexey Kardashevskiy                  ppc_get_vcpu_dt_id(pcpu));
3985a4348d1SPeter Crosthwaite         qemu_fdt_add_subnode(fdt, cpu_name);
3995a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq);
4005a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq);
4015a4348d1SPeter Crosthwaite         qemu_fdt_setprop_string(fdt, cpu_name, "device_type", "cpu");
4020f20ba62SAlexey Kardashevskiy         qemu_fdt_setprop_cell(fdt, cpu_name, "reg",
4030f20ba62SAlexey Kardashevskiy                               ppc_get_vcpu_dt_id(pcpu));
4045a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-line-size",
4051e3debf0SAlexander Graf                               env->dcache_line_size);
4065a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-line-size",
4071e3debf0SAlexander Graf                               env->icache_line_size);
4085a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-size", 0x8000);
4095a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-size", 0x8000);
4105a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "bus-frequency", 0);
41155e5c285SAndreas Färber         if (cpu->cpu_index) {
4125a4348d1SPeter Crosthwaite             qemu_fdt_setprop_string(fdt, cpu_name, "status", "disabled");
4135a4348d1SPeter Crosthwaite             qemu_fdt_setprop_string(fdt, cpu_name, "enable-method",
4145a4348d1SPeter Crosthwaite                                     "spin-table");
4155a4348d1SPeter Crosthwaite             qemu_fdt_setprop_u64(fdt, cpu_name, "cpu-release-addr",
4161d2e5c52SAlexander Graf                                  cpu_release_addr);
4171e3debf0SAlexander Graf         } else {
4185a4348d1SPeter Crosthwaite             qemu_fdt_setprop_string(fdt, cpu_name, "status", "okay");
4191e3debf0SAlexander Graf         }
4201db09b84Saurel32     }
4211db09b84Saurel32 
4225a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, "/aliases");
4235da96624SAlexander Graf     /* XXX These should go into their respective devices' code */
4242eaaac1fSAlexander Graf     snprintf(soc, sizeof(soc), "/soc@%"PRIx64, params->ccsrbar_base);
4255a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, soc);
4265a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, soc, "device_type", "soc");
4275a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, soc, "compatible", compatible_sb,
428ebb9518aSAlexander Graf                      sizeof(compatible_sb));
4295a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, soc, "#address-cells", 1);
4305a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, soc, "#size-cells", 1);
4315a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, soc, "ranges", 0x0,
4322eaaac1fSAlexander Graf                            params->ccsrbar_base >> 32, params->ccsrbar_base,
4335da96624SAlexander Graf                            MPC8544_CCSRBAR_SIZE);
4345da96624SAlexander Graf     /* XXX should contain a reasonable value */
4355a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, soc, "bus-frequency", 0);
4365da96624SAlexander Graf 
437dffb1dc2SBharat Bhushan     snprintf(mpic, sizeof(mpic), "%s/pic@%llx", soc, MPC8544_MPIC_REGS_OFFSET);
4385a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, mpic);
4395a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, mpic, "device_type", "open-pic");
4405a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, mpic, "compatible", "fsl,mpic");
4415a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_OFFSET,
442dffb1dc2SBharat Bhushan                            0x40000);
4435a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, mpic, "#address-cells", 0);
4445a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, mpic, "#interrupt-cells", 2);
4455a4348d1SPeter Crosthwaite     mpic_ph = qemu_fdt_alloc_phandle(fdt);
4465a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, mpic, "phandle", mpic_ph);
4475a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, mpic, "linux,phandle", mpic_ph);
4485a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, mpic, "interrupt-controller", NULL, 0);
44919ac9deaSAlexander Graf 
4500cfc6e8dSAlexander Graf     /*
4510cfc6e8dSAlexander Graf      * We have to generate ser1 first, because Linux takes the first
4520cfc6e8dSAlexander Graf      * device it finds in the dt as serial output device. And we generate
4530cfc6e8dSAlexander Graf      * devices in reverse order to the dt.
4540cfc6e8dSAlexander Graf      */
45579c0ff2cSAlexander Graf     if (serial_hds[1]) {
456dffb1dc2SBharat Bhushan         dt_serial_create(fdt, MPC8544_SERIAL1_REGS_OFFSET,
457a053a7ceSAlexander Graf                          soc, mpic, "serial1", 1, false);
45879c0ff2cSAlexander Graf     }
45979c0ff2cSAlexander Graf 
46079c0ff2cSAlexander Graf     if (serial_hds[0]) {
461dffb1dc2SBharat Bhushan         dt_serial_create(fdt, MPC8544_SERIAL0_REGS_OFFSET,
462a053a7ceSAlexander Graf                          soc, mpic, "serial0", 0, true);
46379c0ff2cSAlexander Graf     }
4640cfc6e8dSAlexander Graf 
465ed2bc496SAlexander Graf     snprintf(gutil, sizeof(gutil), "%s/global-utilities@%llx", soc,
466dffb1dc2SBharat Bhushan              MPC8544_UTIL_OFFSET);
4675a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, gutil);
4685a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, gutil, "compatible", "fsl,mpc8544-guts");
4695a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, gutil, "reg", MPC8544_UTIL_OFFSET, 0x1000);
4705a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, gutil, "fsl,has-rstcr", NULL, 0);
471f5038483SAlexander Graf 
472a911b7a9SAlexander Graf     snprintf(msi, sizeof(msi), "/%s/msi@%llx", soc, MPC8544_MSI_REGS_OFFSET);
4735a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, msi);
4745a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, msi, "compatible", "fsl,mpic-msi");
4755a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, msi, "reg", MPC8544_MSI_REGS_OFFSET, 0x200);
4765a4348d1SPeter Crosthwaite     msi_ph = qemu_fdt_alloc_phandle(fdt);
4775a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, msi, "msi-available-ranges", 0x0, 0x100);
4785a4348d1SPeter Crosthwaite     qemu_fdt_setprop_phandle(fdt, msi, "interrupt-parent", mpic);
4795a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, msi, "interrupts",
480a911b7a9SAlexander Graf         0xe0, 0x0,
481a911b7a9SAlexander Graf         0xe1, 0x0,
482a911b7a9SAlexander Graf         0xe2, 0x0,
483a911b7a9SAlexander Graf         0xe3, 0x0,
484a911b7a9SAlexander Graf         0xe4, 0x0,
485a911b7a9SAlexander Graf         0xe5, 0x0,
486a911b7a9SAlexander Graf         0xe6, 0x0,
487a911b7a9SAlexander Graf         0xe7, 0x0);
4885a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, msi, "phandle", msi_ph);
4895a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, msi, "linux,phandle", msi_ph);
490a911b7a9SAlexander Graf 
4912eaaac1fSAlexander Graf     snprintf(pci, sizeof(pci), "/pci@%llx",
4922eaaac1fSAlexander Graf              params->ccsrbar_base + MPC8544_PCI_REGS_OFFSET);
4935a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, pci);
4945a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "cell-index", 0);
4955a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, pci, "compatible", "fsl,mpc8540-pci");
4965a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, pci, "device_type", "pci");
4975a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, pci, "interrupt-map-mask", 0xf800, 0x0,
4980dbc0798SAlexander Graf                            0x0, 0x7);
4995a4348d1SPeter Crosthwaite     pci_map = pci_map_create(fdt, qemu_fdt_get_phandle(fdt, mpic),
500492ec48dSAlexander Graf                              params->pci_first_slot, params->pci_nr_slots,
501492ec48dSAlexander Graf                              &len);
5025a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, pci, "interrupt-map", pci_map, len);
5035a4348d1SPeter Crosthwaite     qemu_fdt_setprop_phandle(fdt, pci, "interrupt-parent", mpic);
5045a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, pci, "interrupts", 24, 2);
5055a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, pci, "bus-range", 0, 255);
5063627757eSAlexander Graf     for (i = 0; i < 14; i++) {
5070dbc0798SAlexander Graf         pci_ranges[i] = cpu_to_be32(pci_ranges[i]);
5080dbc0798SAlexander Graf     }
5095a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "fsl,msi", msi_ph);
5105a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, pci, "ranges", pci_ranges, sizeof(pci_ranges));
5112eaaac1fSAlexander Graf     qemu_fdt_setprop_cells(fdt, pci, "reg",
5122eaaac1fSAlexander Graf                            (params->ccsrbar_base + MPC8544_PCI_REGS_OFFSET) >> 32,
5132eaaac1fSAlexander Graf                            (params->ccsrbar_base + MPC8544_PCI_REGS_OFFSET),
5142eaaac1fSAlexander Graf                            0, 0x1000);
5155a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "clock-frequency", 66666666);
5165a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "#interrupt-cells", 1);
5175a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "#size-cells", 2);
5185a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "#address-cells", 3);
5195a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, "/aliases", "pci0", pci);
5200dbc0798SAlexander Graf 
521b88e77f4SAlexander Graf     if (params->has_mpc8xxx_gpio) {
522b88e77f4SAlexander Graf         create_dt_mpc8xxx_gpio(fdt, soc, mpic);
523b88e77f4SAlexander Graf     }
524b88e77f4SAlexander Graf 
525f7087343SAlexander Graf     if (params->has_platform_bus) {
526f7087343SAlexander Graf         platform_bus_create_devtree(params, fdt, mpic);
527f7087343SAlexander Graf     }
528f7087343SAlexander Graf 
529e6eaabebSScott Wood     params->fixup_devtree(params, fdt);
530e6eaabebSScott Wood 
531e6eaabebSScott Wood     if (toplevel_compat) {
5325a4348d1SPeter Crosthwaite         qemu_fdt_setprop(fdt, "/", "compatible", toplevel_compat,
533e6eaabebSScott Wood                          strlen(toplevel_compat) + 1);
534e6eaabebSScott Wood     }
535e6eaabebSScott Wood 
536d1b93565SAlexander Graf done:
53728290f37SAlexander Graf     if (!dry_run) {
5385a4348d1SPeter Crosthwaite         qemu_fdt_dumpdtb(fdt, fdt_size);
53928290f37SAlexander Graf         cpu_physical_memory_write(addr, fdt, fdt_size);
540cba2026aSAlexander Graf     }
541cba2026aSAlexander Graf     ret = fdt_size;
5427ec632b4Spbrook 
5431db09b84Saurel32 out:
544347dd79dSAlexander Graf     g_free(pci_map);
5451db09b84Saurel32 
54604088adbSLiu Yu     return ret;
5471db09b84Saurel32 }
5481db09b84Saurel32 
54928290f37SAlexander Graf typedef struct DeviceTreeParams {
5503ef96221SMarcel Apfelbaum     MachineState *machine;
55128290f37SAlexander Graf     PPCE500Params params;
55228290f37SAlexander Graf     hwaddr addr;
55328290f37SAlexander Graf     hwaddr initrd_base;
55428290f37SAlexander Graf     hwaddr initrd_size;
555903585deSAlexander Graf     hwaddr kernel_base;
556903585deSAlexander Graf     hwaddr kernel_size;
557f7087343SAlexander Graf     Notifier notifier;
55828290f37SAlexander Graf } DeviceTreeParams;
55928290f37SAlexander Graf 
56028290f37SAlexander Graf static void ppce500_reset_device_tree(void *opaque)
56128290f37SAlexander Graf {
56228290f37SAlexander Graf     DeviceTreeParams *p = opaque;
5633812c71fSAlexander Graf     ppce500_load_device_tree(p->machine, &p->params, p->addr, p->initrd_base,
564903585deSAlexander Graf                              p->initrd_size, p->kernel_base, p->kernel_size,
565903585deSAlexander Graf                              false);
56628290f37SAlexander Graf }
56728290f37SAlexander Graf 
568f7087343SAlexander Graf static void ppce500_init_notify(Notifier *notifier, void *data)
569f7087343SAlexander Graf {
570f7087343SAlexander Graf     DeviceTreeParams *p = container_of(notifier, DeviceTreeParams, notifier);
571f7087343SAlexander Graf     ppce500_reset_device_tree(p);
572f7087343SAlexander Graf }
573f7087343SAlexander Graf 
5743ef96221SMarcel Apfelbaum static int ppce500_prep_device_tree(MachineState *machine,
57528290f37SAlexander Graf                                     PPCE500Params *params,
57628290f37SAlexander Graf                                     hwaddr addr,
57728290f37SAlexander Graf                                     hwaddr initrd_base,
578903585deSAlexander Graf                                     hwaddr initrd_size,
579903585deSAlexander Graf                                     hwaddr kernel_base,
580903585deSAlexander Graf                                     hwaddr kernel_size)
58128290f37SAlexander Graf {
58228290f37SAlexander Graf     DeviceTreeParams *p = g_new(DeviceTreeParams, 1);
5833ef96221SMarcel Apfelbaum     p->machine = machine;
58428290f37SAlexander Graf     p->params = *params;
58528290f37SAlexander Graf     p->addr = addr;
58628290f37SAlexander Graf     p->initrd_base = initrd_base;
58728290f37SAlexander Graf     p->initrd_size = initrd_size;
588903585deSAlexander Graf     p->kernel_base = kernel_base;
589903585deSAlexander Graf     p->kernel_size = kernel_size;
59028290f37SAlexander Graf 
59128290f37SAlexander Graf     qemu_register_reset(ppce500_reset_device_tree, p);
592f7087343SAlexander Graf     p->notifier.notify = ppce500_init_notify;
593f7087343SAlexander Graf     qemu_add_machine_init_done_notifier(&p->notifier);
59428290f37SAlexander Graf 
59528290f37SAlexander Graf     /* Issue the device tree loader once, so that we get the size of the blob */
5963ef96221SMarcel Apfelbaum     return ppce500_load_device_tree(machine, params, addr, initrd_base,
597903585deSAlexander Graf                                     initrd_size, kernel_base, kernel_size,
598903585deSAlexander Graf                                     true);
59928290f37SAlexander Graf }
60028290f37SAlexander Graf 
601cba2026aSAlexander Graf /* Create -kernel TLB entries for BookE.  */
602a36848ffSAaron Larson hwaddr booke206_page_size_to_tlb(uint64_t size)
603d1e256feSAlexander Graf {
604cba2026aSAlexander Graf     return 63 - clz64(size >> 10);
605d1e256feSAlexander Graf }
606d1e256feSAlexander Graf 
607cefd3cdbSBharat Bhushan static int booke206_initial_map_tsize(CPUPPCState *env)
6083b989d49SAlexander Graf {
609cba2026aSAlexander Graf     struct boot_info *bi = env->load_info;
610cefd3cdbSBharat Bhushan     hwaddr dt_end;
611cba2026aSAlexander Graf     int ps;
6123b989d49SAlexander Graf 
613cba2026aSAlexander Graf     /* Our initial TLB entry needs to cover everything from 0 to
614cba2026aSAlexander Graf        the device tree top */
615cba2026aSAlexander Graf     dt_end = bi->dt_base + bi->dt_size;
616cba2026aSAlexander Graf     ps = booke206_page_size_to_tlb(dt_end) + 1;
617fb37c302SAlexander Graf     if (ps & 1) {
618fb37c302SAlexander Graf         /* e500v2 can only do even TLB size bits */
619fb37c302SAlexander Graf         ps++;
620fb37c302SAlexander Graf     }
621cefd3cdbSBharat Bhushan     return ps;
622cefd3cdbSBharat Bhushan }
623cefd3cdbSBharat Bhushan 
624cefd3cdbSBharat Bhushan static uint64_t mmubooke_initial_mapsize(CPUPPCState *env)
625cefd3cdbSBharat Bhushan {
626cefd3cdbSBharat Bhushan     int tsize;
627cefd3cdbSBharat Bhushan 
628cefd3cdbSBharat Bhushan     tsize = booke206_initial_map_tsize(env);
629cefd3cdbSBharat Bhushan     return (1ULL << 10 << tsize);
630cefd3cdbSBharat Bhushan }
631cefd3cdbSBharat Bhushan 
632cefd3cdbSBharat Bhushan static void mmubooke_create_initial_mapping(CPUPPCState *env)
633cefd3cdbSBharat Bhushan {
634cefd3cdbSBharat Bhushan     ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0);
635cefd3cdbSBharat Bhushan     hwaddr size;
636cefd3cdbSBharat Bhushan     int ps;
637cefd3cdbSBharat Bhushan 
638cefd3cdbSBharat Bhushan     ps = booke206_initial_map_tsize(env);
639cba2026aSAlexander Graf     size = (ps << MAS1_TSIZE_SHIFT);
640d1e256feSAlexander Graf     tlb->mas1 = MAS1_VALID | size;
641cba2026aSAlexander Graf     tlb->mas2 = 0;
642cba2026aSAlexander Graf     tlb->mas7_3 = 0;
643d1e256feSAlexander Graf     tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
64493dd5e85SScott Wood 
64593dd5e85SScott Wood     env->tlb_dirty = true;
6463b989d49SAlexander Graf }
6473b989d49SAlexander Graf 
648b3305981SScott Wood static void ppce500_cpu_reset_sec(void *opaque)
6495c145dacSAlexander Graf {
65038f92da6SAndreas Färber     PowerPCCPU *cpu = opaque;
651259186a7SAndreas Färber     CPUState *cs = CPU(cpu);
6525c145dacSAlexander Graf 
653259186a7SAndreas Färber     cpu_reset(cs);
6545c145dacSAlexander Graf 
6555c145dacSAlexander Graf     /* Secondary CPU starts in halted state for now. Needs to change when
6565c145dacSAlexander Graf        implementing non-kernel boot. */
657259186a7SAndreas Färber     cs->halted = 1;
65827103424SAndreas Färber     cs->exception_index = EXCP_HLT;
6593b989d49SAlexander Graf }
6603b989d49SAlexander Graf 
661b3305981SScott Wood static void ppce500_cpu_reset(void *opaque)
6623b989d49SAlexander Graf {
66338f92da6SAndreas Färber     PowerPCCPU *cpu = opaque;
664259186a7SAndreas Färber     CPUState *cs = CPU(cpu);
66538f92da6SAndreas Färber     CPUPPCState *env = &cpu->env;
6663b989d49SAlexander Graf     struct boot_info *bi = env->load_info;
6673b989d49SAlexander Graf 
668259186a7SAndreas Färber     cpu_reset(cs);
6693b989d49SAlexander Graf 
6703b989d49SAlexander Graf     /* Set initial guest state. */
671259186a7SAndreas Färber     cs->halted = 0;
6723b989d49SAlexander Graf     env->gpr[1] = (16<<20) - 8;
6733b989d49SAlexander Graf     env->gpr[3] = bi->dt_base;
674cefd3cdbSBharat Bhushan     env->gpr[4] = 0;
675cefd3cdbSBharat Bhushan     env->gpr[5] = 0;
676cefd3cdbSBharat Bhushan     env->gpr[6] = EPAPR_MAGIC;
677cefd3cdbSBharat Bhushan     env->gpr[7] = mmubooke_initial_mapsize(env);
678cefd3cdbSBharat Bhushan     env->gpr[8] = 0;
679cefd3cdbSBharat Bhushan     env->gpr[9] = 0;
6803b989d49SAlexander Graf     env->nip = bi->entry;
681cba2026aSAlexander Graf     mmubooke_create_initial_mapping(env);
6823b989d49SAlexander Graf }
6833b989d49SAlexander Graf 
684d85937e6SScott Wood static DeviceState *ppce500_init_mpic_qemu(PPCE500Params *params,
68582fc73b6SScott Wood                                            qemu_irq **irqs)
68682fc73b6SScott Wood {
68782fc73b6SScott Wood     DeviceState *dev;
68882fc73b6SScott Wood     SysBusDevice *s;
68982fc73b6SScott Wood     int i, j, k;
69082fc73b6SScott Wood 
691e1766344SAndreas Färber     dev = qdev_create(NULL, TYPE_OPENPIC);
69282fc73b6SScott Wood     qdev_prop_set_uint32(dev, "model", params->mpic_version);
693d85937e6SScott Wood     qdev_prop_set_uint32(dev, "nb_cpus", smp_cpus);
694d85937e6SScott Wood 
69582fc73b6SScott Wood     qdev_init_nofail(dev);
69682fc73b6SScott Wood     s = SYS_BUS_DEVICE(dev);
69782fc73b6SScott Wood 
69882fc73b6SScott Wood     k = 0;
69982fc73b6SScott Wood     for (i = 0; i < smp_cpus; i++) {
70082fc73b6SScott Wood         for (j = 0; j < OPENPIC_OUTPUT_NB; j++) {
70182fc73b6SScott Wood             sysbus_connect_irq(s, k++, irqs[i][j]);
70282fc73b6SScott Wood         }
70382fc73b6SScott Wood     }
70482fc73b6SScott Wood 
705d85937e6SScott Wood     return dev;
706d85937e6SScott Wood }
707d85937e6SScott Wood 
708d85937e6SScott Wood static DeviceState *ppce500_init_mpic_kvm(PPCE500Params *params,
709fe656ebdSMarkus Armbruster                                           qemu_irq **irqs, Error **errp)
710d85937e6SScott Wood {
711fe656ebdSMarkus Armbruster     Error *err = NULL;
712d85937e6SScott Wood     DeviceState *dev;
713d85937e6SScott Wood     CPUState *cs;
714d85937e6SScott Wood 
715dd49c038SAndreas Färber     dev = qdev_create(NULL, TYPE_KVM_OPENPIC);
716d85937e6SScott Wood     qdev_prop_set_uint32(dev, "model", params->mpic_version);
717d85937e6SScott Wood 
718fe656ebdSMarkus Armbruster     object_property_set_bool(OBJECT(dev), true, "realized", &err);
719fe656ebdSMarkus Armbruster     if (err) {
720fe656ebdSMarkus Armbruster         error_propagate(errp, err);
721fe656ebdSMarkus Armbruster         object_unparent(OBJECT(dev));
722d85937e6SScott Wood         return NULL;
723d85937e6SScott Wood     }
724d85937e6SScott Wood 
725bdc44640SAndreas Färber     CPU_FOREACH(cs) {
726d85937e6SScott Wood         if (kvm_openpic_connect_vcpu(dev, cs)) {
727d85937e6SScott Wood             fprintf(stderr, "%s: failed to connect vcpu to irqchip\n",
728d85937e6SScott Wood                     __func__);
729d85937e6SScott Wood             abort();
730d85937e6SScott Wood         }
731d85937e6SScott Wood     }
732d85937e6SScott Wood 
733d85937e6SScott Wood     return dev;
734d85937e6SScott Wood }
735d85937e6SScott Wood 
736446f16a6SMarcel Apfelbaum static qemu_irq *ppce500_init_mpic(MachineState *machine, PPCE500Params *params,
737446f16a6SMarcel Apfelbaum                                    MemoryRegion *ccsr, qemu_irq **irqs)
738d85937e6SScott Wood {
739d85937e6SScott Wood     qemu_irq *mpic;
740d85937e6SScott Wood     DeviceState *dev = NULL;
741d85937e6SScott Wood     SysBusDevice *s;
742d85937e6SScott Wood     int i;
743d85937e6SScott Wood 
744aa2ac1daSPeter Crosthwaite     mpic = g_new0(qemu_irq, 256);
745d85937e6SScott Wood 
746d85937e6SScott Wood     if (kvm_enabled()) {
747fe656ebdSMarkus Armbruster         Error *err = NULL;
748d85937e6SScott Wood 
749446f16a6SMarcel Apfelbaum         if (machine_kernel_irqchip_allowed(machine)) {
750fe656ebdSMarkus Armbruster             dev = ppce500_init_mpic_kvm(params, irqs, &err);
751d85937e6SScott Wood         }
752446f16a6SMarcel Apfelbaum         if (machine_kernel_irqchip_required(machine) && !dev) {
753c29b77f9SMarkus Armbruster             error_reportf_err(err,
754c29b77f9SMarkus Armbruster                               "kernel_irqchip requested but unavailable: ");
755fe656ebdSMarkus Armbruster             exit(1);
756d85937e6SScott Wood         }
757d85937e6SScott Wood     }
758d85937e6SScott Wood 
759d85937e6SScott Wood     if (!dev) {
760d85937e6SScott Wood         dev = ppce500_init_mpic_qemu(params, irqs);
761d85937e6SScott Wood     }
762d85937e6SScott Wood 
76382fc73b6SScott Wood     for (i = 0; i < 256; i++) {
76482fc73b6SScott Wood         mpic[i] = qdev_get_gpio_in(dev, i);
76582fc73b6SScott Wood     }
76682fc73b6SScott Wood 
767d85937e6SScott Wood     s = SYS_BUS_DEVICE(dev);
76882fc73b6SScott Wood     memory_region_add_subregion(ccsr, MPC8544_MPIC_REGS_OFFSET,
76982fc73b6SScott Wood                                 s->mmio[0].memory);
77082fc73b6SScott Wood 
77182fc73b6SScott Wood     return mpic;
77282fc73b6SScott Wood }
77382fc73b6SScott Wood 
774016f7758SAlexander Graf static void ppce500_power_off(void *opaque, int line, int on)
775016f7758SAlexander Graf {
776016f7758SAlexander Graf     if (on) {
777*cf83f140SEric Blake         qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
778016f7758SAlexander Graf     }
779016f7758SAlexander Graf }
780016f7758SAlexander Graf 
7813ef96221SMarcel Apfelbaum void ppce500_init(MachineState *machine, PPCE500Params *params)
7821db09b84Saurel32 {
78339186d8aSRichard Henderson     MemoryRegion *address_space_mem = get_system_memory();
7842646c133SAvi Kivity     MemoryRegion *ram = g_new(MemoryRegion, 1);
7851db09b84Saurel32     PCIBus *pci_bus;
786e2684c0bSAndreas Färber     CPUPPCState *env = NULL;
7873812c71fSAlexander Graf     uint64_t loadaddr;
7883812c71fSAlexander Graf     hwaddr kernel_base = -1LL;
7893812c71fSAlexander Graf     int kernel_size = 0;
7903812c71fSAlexander Graf     hwaddr dt_base = 0;
7913812c71fSAlexander Graf     hwaddr initrd_base = 0;
7923812c71fSAlexander Graf     int initrd_size = 0;
7933812c71fSAlexander Graf     hwaddr cur_base = 0;
7943812c71fSAlexander Graf     char *filename;
7953812c71fSAlexander Graf     hwaddr bios_entry = 0;
7963812c71fSAlexander Graf     target_long bios_size;
7973812c71fSAlexander Graf     struct boot_info *boot_info;
7983812c71fSAlexander Graf     int dt_size;
79982fc73b6SScott Wood     int i;
800d575a6ceSBharat Bhushan     /* irq num for pin INTA, INTB, INTC and INTD is 1, 2, 3 and
801d575a6ceSBharat Bhushan      * 4 respectively */
802d575a6ceSBharat Bhushan     unsigned int pci_irq_nrs[PCI_NUM_PINS] = {1, 2, 3, 4};
803a915249fSAlexander Graf     qemu_irq **irqs, *mpic;
804be13cc7aSAlexander Graf     DeviceState *dev;
805e2684c0bSAndreas Färber     CPUPPCState *firstenv = NULL;
8063eddc1beSBharat Bhushan     MemoryRegion *ccsr_addr_space;
807dffb1dc2SBharat Bhushan     SysBusDevice *s;
8083eddc1beSBharat Bhushan     PPCE500CCSRState *ccsr;
8091db09b84Saurel32 
810e61c36d5SAlexander Graf     /* Setup CPUs */
8113ef96221SMarcel Apfelbaum     if (machine->cpu_model == NULL) {
8123ef96221SMarcel Apfelbaum         machine->cpu_model = "e500v2_v30";
813ef250db6SAlexander Graf     }
814ef250db6SAlexander Graf 
815a915249fSAlexander Graf     irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *));
816a915249fSAlexander Graf     irqs[0] = g_malloc0(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
817e61c36d5SAlexander Graf     for (i = 0; i < smp_cpus; i++) {
818397b457dSAndreas Färber         PowerPCCPU *cpu;
81955e5c285SAndreas Färber         CPUState *cs;
820e61c36d5SAlexander Graf         qemu_irq *input;
821397b457dSAndreas Färber 
8223ef96221SMarcel Apfelbaum         cpu = cpu_ppc_init(machine->cpu_model);
823397b457dSAndreas Färber         if (cpu == NULL) {
8241db09b84Saurel32             fprintf(stderr, "Unable to initialize CPU!\n");
8251db09b84Saurel32             exit(1);
8261db09b84Saurel32         }
827397b457dSAndreas Färber         env = &cpu->env;
82855e5c285SAndreas Färber         cs = CPU(cpu);
8291db09b84Saurel32 
83000469dc3SValentin Plotkin         if (env->mmu_model != POWERPC_MMU_BOOKE206) {
83100469dc3SValentin Plotkin             fprintf(stderr, "MMU model %i not supported by this machine.\n",
83200469dc3SValentin Plotkin                 env->mmu_model);
83300469dc3SValentin Plotkin             exit(1);
83400469dc3SValentin Plotkin         }
83500469dc3SValentin Plotkin 
836e61c36d5SAlexander Graf         if (!firstenv) {
837e61c36d5SAlexander Graf             firstenv = env;
838e61c36d5SAlexander Graf         }
839e61c36d5SAlexander Graf 
840a915249fSAlexander Graf         irqs[i] = irqs[0] + (i * OPENPIC_OUTPUT_NB);
841a915249fSAlexander Graf         input = (qemu_irq *)env->irq_inputs;
842a915249fSAlexander Graf         irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT];
843a915249fSAlexander Graf         irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT];
8446a450df9SAlexander Graf         env->spr_cb[SPR_BOOKE_PIR].default_value = cs->cpu_index = i;
8452eaaac1fSAlexander Graf         env->mpic_iack = params->ccsrbar_base +
846bd25922eSScott Wood                          MPC8544_MPIC_REGS_OFFSET + 0xa0;
847e61c36d5SAlexander Graf 
848a34a92b9SAndreas Färber         ppc_booke_timers_init(cpu, 400000000, PPC_TIMER_E500);
8493b989d49SAlexander Graf 
8503b989d49SAlexander Graf         /* Register reset handler */
8515c145dacSAlexander Graf         if (!i) {
8525c145dacSAlexander Graf             /* Primary CPU */
8535c145dacSAlexander Graf             struct boot_info *boot_info;
854e61c36d5SAlexander Graf             boot_info = g_malloc0(sizeof(struct boot_info));
855b3305981SScott Wood             qemu_register_reset(ppce500_cpu_reset, cpu);
856e61c36d5SAlexander Graf             env->load_info = boot_info;
8575c145dacSAlexander Graf         } else {
8585c145dacSAlexander Graf             /* Secondary CPUs */
859b3305981SScott Wood             qemu_register_reset(ppce500_cpu_reset_sec, cpu);
8605c145dacSAlexander Graf         }
861e61c36d5SAlexander Graf     }
862e61c36d5SAlexander Graf 
863e61c36d5SAlexander Graf     env = firstenv;
8643b989d49SAlexander Graf 
8651db09b84Saurel32     /* Fixup Memory size on a alignment boundary */
8661db09b84Saurel32     ram_size &= ~(RAM_SIZES_ALIGN - 1);
8673ef96221SMarcel Apfelbaum     machine->ram_size = ram_size;
8681db09b84Saurel32 
8691db09b84Saurel32     /* Register Memory */
870e938ba0cSShreyas B. Prabhu     memory_region_allocate_system_memory(ram, NULL, "mpc8544ds.ram", ram_size);
8712646c133SAvi Kivity     memory_region_add_subregion(address_space_mem, 0, ram);
8721db09b84Saurel32 
8733eddc1beSBharat Bhushan     dev = qdev_create(NULL, "e500-ccsr");
8743eddc1beSBharat Bhushan     object_property_add_child(qdev_get_machine(), "e500-ccsr",
8753eddc1beSBharat Bhushan                               OBJECT(dev), NULL);
8763eddc1beSBharat Bhushan     qdev_init_nofail(dev);
8773eddc1beSBharat Bhushan     ccsr = CCSR(dev);
8783eddc1beSBharat Bhushan     ccsr_addr_space = &ccsr->ccsr_space;
8792eaaac1fSAlexander Graf     memory_region_add_subregion(address_space_mem, params->ccsrbar_base,
8803eddc1beSBharat Bhushan                                 ccsr_addr_space);
881dffb1dc2SBharat Bhushan 
882446f16a6SMarcel Apfelbaum     mpic = ppce500_init_mpic(machine, params, ccsr_addr_space, irqs);
8831db09b84Saurel32 
8841db09b84Saurel32     /* Serial */
8852d48377aSBlue Swirl     if (serial_hds[0]) {
8863eddc1beSBharat Bhushan         serial_mm_init(ccsr_addr_space, MPC8544_SERIAL0_REGS_OFFSET,
887cdbb912aSAlexander Graf                        0, mpic[42], 399193,
8882ff0c7c3SRichard Henderson                        serial_hds[0], DEVICE_BIG_ENDIAN);
8892d48377aSBlue Swirl     }
8901db09b84Saurel32 
8912d48377aSBlue Swirl     if (serial_hds[1]) {
8923eddc1beSBharat Bhushan         serial_mm_init(ccsr_addr_space, MPC8544_SERIAL1_REGS_OFFSET,
893cdbb912aSAlexander Graf                        0, mpic[42], 399193,
89459de4f98SBharat Bhushan                        serial_hds[1], DEVICE_BIG_ENDIAN);
8952d48377aSBlue Swirl     }
8961db09b84Saurel32 
897b0fb8423SAlexander Graf     /* General Utility device */
898dffb1dc2SBharat Bhushan     dev = qdev_create(NULL, "mpc8544-guts");
899dffb1dc2SBharat Bhushan     qdev_init_nofail(dev);
900dffb1dc2SBharat Bhushan     s = SYS_BUS_DEVICE(dev);
9013eddc1beSBharat Bhushan     memory_region_add_subregion(ccsr_addr_space, MPC8544_UTIL_OFFSET,
902dffb1dc2SBharat Bhushan                                 sysbus_mmio_get_region(s, 0));
903b0fb8423SAlexander Graf 
9041db09b84Saurel32     /* PCI */
905dffb1dc2SBharat Bhushan     dev = qdev_create(NULL, "e500-pcihost");
906492ec48dSAlexander Graf     qdev_prop_set_uint32(dev, "first_slot", params->pci_first_slot);
9073016dca0SBharat Bhushan     qdev_prop_set_uint32(dev, "first_pin_irq", pci_irq_nrs[0]);
908dffb1dc2SBharat Bhushan     qdev_init_nofail(dev);
909dffb1dc2SBharat Bhushan     s = SYS_BUS_DEVICE(dev);
910d575a6ceSBharat Bhushan     for (i = 0; i < PCI_NUM_PINS; i++) {
911d575a6ceSBharat Bhushan         sysbus_connect_irq(s, i, mpic[pci_irq_nrs[i]]);
912d575a6ceSBharat Bhushan     }
913d575a6ceSBharat Bhushan 
9143eddc1beSBharat Bhushan     memory_region_add_subregion(ccsr_addr_space, MPC8544_PCI_REGS_OFFSET,
915dffb1dc2SBharat Bhushan                                 sysbus_mmio_get_region(s, 0));
916dffb1dc2SBharat Bhushan 
917d461e3b9SAlexander Graf     pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
9181db09b84Saurel32     if (!pci_bus)
9191db09b84Saurel32         printf("couldn't create PCI controller!\n");
9201db09b84Saurel32 
9211db09b84Saurel32     if (pci_bus) {
9221db09b84Saurel32         /* Register network interfaces. */
9231db09b84Saurel32         for (i = 0; i < nb_nics; i++) {
92429b358f9SDavid Gibson             pci_nic_init_nofail(&nd_table[i], pci_bus, "virtio", NULL);
9251db09b84Saurel32         }
9261db09b84Saurel32     }
9271db09b84Saurel32 
9285c145dacSAlexander Graf     /* Register spinning region */
9292eaaac1fSAlexander Graf     sysbus_create_simple("e500-spin", params->spin_base, NULL);
9305c145dacSAlexander Graf 
9313812c71fSAlexander Graf     if (cur_base < (32 * 1024 * 1024)) {
9323812c71fSAlexander Graf         /* u-boot occupies memory up to 32MB, so load blobs above */
9333812c71fSAlexander Graf         cur_base = (32 * 1024 * 1024);
9343812c71fSAlexander Graf     }
9353812c71fSAlexander Graf 
936b88e77f4SAlexander Graf     if (params->has_mpc8xxx_gpio) {
937016f7758SAlexander Graf         qemu_irq poweroff_irq;
938016f7758SAlexander Graf 
939b88e77f4SAlexander Graf         dev = qdev_create(NULL, "mpc8xxx_gpio");
940b88e77f4SAlexander Graf         s = SYS_BUS_DEVICE(dev);
941b88e77f4SAlexander Graf         qdev_init_nofail(dev);
942b88e77f4SAlexander Graf         sysbus_connect_irq(s, 0, mpic[MPC8XXX_GPIO_IRQ]);
943b88e77f4SAlexander Graf         memory_region_add_subregion(ccsr_addr_space, MPC8XXX_GPIO_OFFSET,
944b88e77f4SAlexander Graf                                     sysbus_mmio_get_region(s, 0));
945016f7758SAlexander Graf 
946016f7758SAlexander Graf         /* Power Off GPIO at Pin 0 */
947016f7758SAlexander Graf         poweroff_irq = qemu_allocate_irq(ppce500_power_off, NULL, 0);
948016f7758SAlexander Graf         qdev_connect_gpio_out(dev, 0, poweroff_irq);
949b88e77f4SAlexander Graf     }
950b88e77f4SAlexander Graf 
951f7087343SAlexander Graf     /* Platform Bus Device */
952f7087343SAlexander Graf     if (params->has_platform_bus) {
953f7087343SAlexander Graf         dev = qdev_create(NULL, TYPE_PLATFORM_BUS_DEVICE);
954f7087343SAlexander Graf         dev->id = TYPE_PLATFORM_BUS_DEVICE;
955f7087343SAlexander Graf         qdev_prop_set_uint32(dev, "num_irqs", params->platform_bus_num_irqs);
956f7087343SAlexander Graf         qdev_prop_set_uint32(dev, "mmio_size", params->platform_bus_size);
957f7087343SAlexander Graf         qdev_init_nofail(dev);
958f7087343SAlexander Graf         s = SYS_BUS_DEVICE(dev);
959f7087343SAlexander Graf 
960f7087343SAlexander Graf         for (i = 0; i < params->platform_bus_num_irqs; i++) {
961f7087343SAlexander Graf             int irqn = params->platform_bus_first_irq + i;
962f7087343SAlexander Graf             sysbus_connect_irq(s, i, mpic[irqn]);
963f7087343SAlexander Graf         }
964f7087343SAlexander Graf 
965f7087343SAlexander Graf         memory_region_add_subregion(address_space_mem,
966f7087343SAlexander Graf                                     params->platform_bus_base,
967f7087343SAlexander Graf                                     sysbus_mmio_get_region(s, 0));
968f7087343SAlexander Graf     }
969f7087343SAlexander Graf 
9701db09b84Saurel32     /* Load kernel. */
9713ef96221SMarcel Apfelbaum     if (machine->kernel_filename) {
9723812c71fSAlexander Graf         kernel_base = cur_base;
9733812c71fSAlexander Graf         kernel_size = load_image_targphys(machine->kernel_filename,
9743812c71fSAlexander Graf                                           cur_base,
9753812c71fSAlexander Graf                                           ram_size - cur_base);
9761db09b84Saurel32         if (kernel_size < 0) {
9771db09b84Saurel32             fprintf(stderr, "qemu: could not load kernel '%s'\n",
9783ef96221SMarcel Apfelbaum                     machine->kernel_filename);
9791db09b84Saurel32             exit(1);
9801db09b84Saurel32         }
981528e536eSAlexander Graf 
9823812c71fSAlexander Graf         cur_base += kernel_size;
9831db09b84Saurel32     }
9841db09b84Saurel32 
9851db09b84Saurel32     /* Load initrd. */
9863ef96221SMarcel Apfelbaum     if (machine->initrd_filename) {
987528e536eSAlexander Graf         initrd_base = (cur_base + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK;
9883ef96221SMarcel Apfelbaum         initrd_size = load_image_targphys(machine->initrd_filename, initrd_base,
989d7585251Spbrook                                           ram_size - initrd_base);
9901db09b84Saurel32 
9911db09b84Saurel32         if (initrd_size < 0) {
9921db09b84Saurel32             fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
9933ef96221SMarcel Apfelbaum                     machine->initrd_filename);
9941db09b84Saurel32             exit(1);
9951db09b84Saurel32         }
996528e536eSAlexander Graf 
997528e536eSAlexander Graf         cur_base = initrd_base + initrd_size;
9981db09b84Saurel32     }
9991db09b84Saurel32 
10003812c71fSAlexander Graf     /*
10013812c71fSAlexander Graf      * Smart firmware defaults ahead!
10023812c71fSAlexander Graf      *
10033812c71fSAlexander Graf      * We follow the following table to select which payload we execute.
10043812c71fSAlexander Graf      *
10053812c71fSAlexander Graf      *  -kernel | -bios | payload
10063812c71fSAlexander Graf      * ---------+-------+---------
10073812c71fSAlexander Graf      *     N    |   Y   | u-boot
10083812c71fSAlexander Graf      *     N    |   N   | u-boot
10093812c71fSAlexander Graf      *     Y    |   Y   | u-boot
10103812c71fSAlexander Graf      *     Y    |   N   | kernel
10113812c71fSAlexander Graf      *
10123812c71fSAlexander Graf      * This ensures backwards compatibility with how we used to expose
10133812c71fSAlexander Graf      * -kernel to users but allows them to run through u-boot as well.
10143812c71fSAlexander Graf      */
10153812c71fSAlexander Graf     if (bios_name == NULL) {
10163ef96221SMarcel Apfelbaum         if (machine->kernel_filename) {
10173812c71fSAlexander Graf             bios_name = machine->kernel_filename;
10183812c71fSAlexander Graf         } else {
10193812c71fSAlexander Graf             bios_name = "u-boot.e500";
10203812c71fSAlexander Graf         }
10213812c71fSAlexander Graf     }
10223812c71fSAlexander Graf     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
10233812c71fSAlexander Graf 
10243812c71fSAlexander Graf     bios_size = load_elf(filename, NULL, NULL, &bios_entry, &loadaddr, NULL,
10257ef295eaSPeter Crosthwaite                          1, PPC_ELF_MACHINE, 0, 0);
10263812c71fSAlexander Graf     if (bios_size < 0) {
10273812c71fSAlexander Graf         /*
10283812c71fSAlexander Graf          * Hrm. No ELF image? Try a uImage, maybe someone is giving us an
10293812c71fSAlexander Graf          * ePAPR compliant kernel
10303812c71fSAlexander Graf          */
103125bda50aSMax Filippov         kernel_size = load_uimage(filename, &bios_entry, &loadaddr, NULL,
103225bda50aSMax Filippov                                   NULL, NULL);
10333812c71fSAlexander Graf         if (kernel_size < 0) {
10343812c71fSAlexander Graf             fprintf(stderr, "qemu: could not load firmware '%s'\n", filename);
10353812c71fSAlexander Graf             exit(1);
10363812c71fSAlexander Graf         }
10373812c71fSAlexander Graf     }
1038f19377bfSShannon Zhao     g_free(filename);
10393812c71fSAlexander Graf 
10403812c71fSAlexander Graf     /* Reserve space for dtb */
10413812c71fSAlexander Graf     dt_base = (loadaddr + bios_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
10425c145dacSAlexander Graf 
10433ef96221SMarcel Apfelbaum     dt_size = ppce500_prep_device_tree(machine, params, dt_base,
1044903585deSAlexander Graf                                        initrd_base, initrd_size,
10453812c71fSAlexander Graf                                        kernel_base, kernel_size);
1046cba2026aSAlexander Graf     if (dt_size < 0) {
10471db09b84Saurel32         fprintf(stderr, "couldn't load device tree\n");
10481db09b84Saurel32         exit(1);
10491db09b84Saurel32     }
1050b8dec144SAlexander Graf     assert(dt_size < DTB_MAX_SIZE);
10511db09b84Saurel32 
1052e61c36d5SAlexander Graf     boot_info = env->load_info;
10533812c71fSAlexander Graf     boot_info->entry = bios_entry;
10543b989d49SAlexander Graf     boot_info->dt_base = dt_base;
1055cba2026aSAlexander Graf     boot_info->dt_size = dt_size;
10561db09b84Saurel32 }
10573eddc1beSBharat Bhushan 
1058d0c2b0d0Sxiaoqiang zhao static void e500_ccsr_initfn(Object *obj)
10593eddc1beSBharat Bhushan {
1060d0c2b0d0Sxiaoqiang zhao     PPCE500CCSRState *ccsr = CCSR(obj);
1061d0c2b0d0Sxiaoqiang zhao     memory_region_init(&ccsr->ccsr_space, obj, "e500-ccsr",
10623eddc1beSBharat Bhushan                        MPC8544_CCSRBAR_SIZE);
10633eddc1beSBharat Bhushan }
10643eddc1beSBharat Bhushan 
10653eddc1beSBharat Bhushan static const TypeInfo e500_ccsr_info = {
10663eddc1beSBharat Bhushan     .name          = TYPE_CCSR,
10673eddc1beSBharat Bhushan     .parent        = TYPE_SYS_BUS_DEVICE,
10683eddc1beSBharat Bhushan     .instance_size = sizeof(PPCE500CCSRState),
1069d0c2b0d0Sxiaoqiang zhao     .instance_init = e500_ccsr_initfn,
10703eddc1beSBharat Bhushan };
10713eddc1beSBharat Bhushan 
10723eddc1beSBharat Bhushan static void e500_register_types(void)
10733eddc1beSBharat Bhushan {
10743eddc1beSBharat Bhushan     type_register_static(&e500_ccsr_info);
10753eddc1beSBharat Bhushan }
10763eddc1beSBharat Bhushan 
10773eddc1beSBharat Bhushan type_init(e500_register_types)
1078