xref: /qemu/hw/ppc/e500.c (revision c29b77f955ff2f7b57c1e71e9dc26243eefd0b28)
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 
171db09b84Saurel32 #include "config.h"
181db09b84Saurel32 #include "qemu-common.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"
320d09e41aSPaolo Bonzini #include "hw/ppc/ppc.h"
334a18e7c9SScott Wood #include "hw/loader.h"
34ca20cf32SBlue Swirl #include "elf.h"
354a18e7c9SScott Wood #include "hw/sysbus.h"
36022c62cbSPaolo Bonzini #include "exec/address-spaces.h"
371de7afc9SPaolo Bonzini #include "qemu/host-utils.h"
380d09e41aSPaolo Bonzini #include "hw/pci-host/ppce500.h"
39f7087343SAlexander Graf #include "qemu/error-report.h"
40f7087343SAlexander Graf #include "hw/platform-bus.h"
41fdfb7f2cSAlexander Graf #include "hw/net/fsl_etsec/etsec.h"
421db09b84Saurel32 
43cefd3cdbSBharat Bhushan #define EPAPR_MAGIC                (0x45504150)
441db09b84Saurel32 #define BINARY_DEVICE_TREE_FILE    "mpc8544ds.dtb"
459dd5eba1SScott Wood #define DTC_LOAD_PAD               0x1800000
4675bb6589SLiu Yu #define DTC_PAD_MASK               0xFFFFF
47b8dec144SAlexander Graf #define DTB_MAX_SIZE               (8 * 1024 * 1024)
4875bb6589SLiu Yu #define INITRD_LOAD_PAD            0x2000000
4975bb6589SLiu Yu #define INITRD_PAD_MASK            0xFFFFFF
501db09b84Saurel32 
511db09b84Saurel32 #define RAM_SIZES_ALIGN            (64UL << 20)
521db09b84Saurel32 
53b3305981SScott Wood /* TODO: parameterize */
54ed2bc496SAlexander Graf #define MPC8544_CCSRBAR_SIZE       0x00100000ULL
55dffb1dc2SBharat Bhushan #define MPC8544_MPIC_REGS_OFFSET   0x40000ULL
56a911b7a9SAlexander Graf #define MPC8544_MSI_REGS_OFFSET   0x41600ULL
57dffb1dc2SBharat Bhushan #define MPC8544_SERIAL0_REGS_OFFSET 0x4500ULL
58dffb1dc2SBharat Bhushan #define MPC8544_SERIAL1_REGS_OFFSET 0x4600ULL
59dffb1dc2SBharat Bhushan #define MPC8544_PCI_REGS_OFFSET    0x8000ULL
60ed2bc496SAlexander Graf #define MPC8544_PCI_REGS_SIZE      0x1000ULL
61dffb1dc2SBharat Bhushan #define MPC8544_UTIL_OFFSET        0xe0000ULL
62b88e77f4SAlexander Graf #define MPC8XXX_GPIO_OFFSET        0x000FF000ULL
6382e345f5SAmit Tomar #define MPC8XXX_GPIO_IRQ           47
641db09b84Saurel32 
653b989d49SAlexander Graf struct boot_info
663b989d49SAlexander Graf {
673b989d49SAlexander Graf     uint32_t dt_base;
68cba2026aSAlexander Graf     uint32_t dt_size;
693b989d49SAlexander Graf     uint32_t entry;
703b989d49SAlexander Graf };
713b989d49SAlexander Graf 
72347dd79dSAlexander Graf static uint32_t *pci_map_create(void *fdt, uint32_t mpic, int first_slot,
73347dd79dSAlexander Graf                                 int nr_slots, int *len)
740dbc0798SAlexander Graf {
75347dd79dSAlexander Graf     int i = 0;
76347dd79dSAlexander Graf     int slot;
77347dd79dSAlexander Graf     int pci_irq;
789e2c1298SAlexander Graf     int host_irq;
79347dd79dSAlexander Graf     int last_slot = first_slot + nr_slots;
80347dd79dSAlexander Graf     uint32_t *pci_map;
810dbc0798SAlexander Graf 
82347dd79dSAlexander Graf     *len = nr_slots * 4 * 7 * sizeof(uint32_t);
83347dd79dSAlexander Graf     pci_map = g_malloc(*len);
84347dd79dSAlexander Graf 
85347dd79dSAlexander Graf     for (slot = first_slot; slot < last_slot; slot++) {
86347dd79dSAlexander Graf         for (pci_irq = 0; pci_irq < 4; pci_irq++) {
87347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(slot << 11);
88347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(0x0);
89347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(0x0);
90347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(pci_irq + 1);
91347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(mpic);
929e2c1298SAlexander Graf             host_irq = ppce500_pci_map_irq_slot(slot, pci_irq);
939e2c1298SAlexander Graf             pci_map[i++] = cpu_to_be32(host_irq + 1);
94347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(0x1);
950dbc0798SAlexander Graf         }
960dbc0798SAlexander Graf     }
970dbc0798SAlexander Graf 
98347dd79dSAlexander Graf     assert((i * sizeof(uint32_t)) == *len);
99347dd79dSAlexander Graf 
100347dd79dSAlexander Graf     return pci_map;
101347dd79dSAlexander Graf }
102347dd79dSAlexander Graf 
103a053a7ceSAlexander Graf static void dt_serial_create(void *fdt, unsigned long long offset,
104a053a7ceSAlexander Graf                              const char *soc, const char *mpic,
105a053a7ceSAlexander Graf                              const char *alias, int idx, bool defcon)
106a053a7ceSAlexander Graf {
107a053a7ceSAlexander Graf     char ser[128];
108a053a7ceSAlexander Graf 
109a053a7ceSAlexander Graf     snprintf(ser, sizeof(ser), "%s/serial@%llx", soc, offset);
1105a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, ser);
1115a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, ser, "device_type", "serial");
1125a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, ser, "compatible", "ns16550");
1135a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, ser, "reg", offset, 0x100);
1145a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, ser, "cell-index", idx);
1155a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, ser, "clock-frequency", 0);
1165a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, ser, "interrupts", 42, 2);
1175a4348d1SPeter Crosthwaite     qemu_fdt_setprop_phandle(fdt, ser, "interrupt-parent", mpic);
1185a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, "/aliases", alias, ser);
119a053a7ceSAlexander Graf 
120a053a7ceSAlexander Graf     if (defcon) {
1215a4348d1SPeter Crosthwaite         qemu_fdt_setprop_string(fdt, "/chosen", "linux,stdout-path", ser);
122a053a7ceSAlexander Graf     }
123a053a7ceSAlexander Graf }
124a053a7ceSAlexander Graf 
125b88e77f4SAlexander Graf static void create_dt_mpc8xxx_gpio(void *fdt, const char *soc, const char *mpic)
126b88e77f4SAlexander Graf {
127b88e77f4SAlexander Graf     hwaddr mmio0 = MPC8XXX_GPIO_OFFSET;
128b88e77f4SAlexander Graf     int irq0 = MPC8XXX_GPIO_IRQ;
129b88e77f4SAlexander Graf     gchar *node = g_strdup_printf("%s/gpio@%"PRIx64, soc, mmio0);
130016f7758SAlexander Graf     gchar *poweroff = g_strdup_printf("%s/power-off", soc);
131016f7758SAlexander Graf     int gpio_ph;
132b88e77f4SAlexander Graf 
133b88e77f4SAlexander Graf     qemu_fdt_add_subnode(fdt, node);
134b88e77f4SAlexander Graf     qemu_fdt_setprop_string(fdt, node, "compatible", "fsl,qoriq-gpio");
135b88e77f4SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "reg", mmio0, 0x1000);
136b88e77f4SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "interrupts", irq0, 0x2);
137b88e77f4SAlexander Graf     qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", mpic);
138b88e77f4SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "#gpio-cells", 2);
139b88e77f4SAlexander Graf     qemu_fdt_setprop(fdt, node, "gpio-controller", NULL, 0);
140016f7758SAlexander Graf     gpio_ph = qemu_fdt_alloc_phandle(fdt);
141016f7758SAlexander Graf     qemu_fdt_setprop_cell(fdt, node, "phandle", gpio_ph);
142016f7758SAlexander Graf     qemu_fdt_setprop_cell(fdt, node, "linux,phandle", gpio_ph);
143016f7758SAlexander Graf 
144016f7758SAlexander Graf     /* Power Off Pin */
145016f7758SAlexander Graf     qemu_fdt_add_subnode(fdt, poweroff);
146016f7758SAlexander Graf     qemu_fdt_setprop_string(fdt, poweroff, "compatible", "gpio-poweroff");
147016f7758SAlexander Graf     qemu_fdt_setprop_cells(fdt, poweroff, "gpios", gpio_ph, 0, 0);
148b88e77f4SAlexander Graf 
149b88e77f4SAlexander Graf     g_free(node);
150016f7758SAlexander Graf     g_free(poweroff);
151b88e77f4SAlexander Graf }
152b88e77f4SAlexander Graf 
153f7087343SAlexander Graf typedef struct PlatformDevtreeData {
154f7087343SAlexander Graf     void *fdt;
155f7087343SAlexander Graf     const char *mpic;
156f7087343SAlexander Graf     int irq_start;
157f7087343SAlexander Graf     const char *node;
158f7087343SAlexander Graf     PlatformBusDevice *pbus;
159f7087343SAlexander Graf } PlatformDevtreeData;
160f7087343SAlexander Graf 
161fdfb7f2cSAlexander Graf static int create_devtree_etsec(SysBusDevice *sbdev, PlatformDevtreeData *data)
162fdfb7f2cSAlexander Graf {
163fdfb7f2cSAlexander Graf     eTSEC *etsec = ETSEC_COMMON(sbdev);
164fdfb7f2cSAlexander Graf     PlatformBusDevice *pbus = data->pbus;
165fdfb7f2cSAlexander Graf     hwaddr mmio0 = platform_bus_get_mmio_addr(pbus, sbdev, 0);
166fdfb7f2cSAlexander Graf     int irq0 = platform_bus_get_irqn(pbus, sbdev, 0);
167fdfb7f2cSAlexander Graf     int irq1 = platform_bus_get_irqn(pbus, sbdev, 1);
168fdfb7f2cSAlexander Graf     int irq2 = platform_bus_get_irqn(pbus, sbdev, 2);
169fdfb7f2cSAlexander Graf     gchar *node = g_strdup_printf("/platform/ethernet@%"PRIx64, mmio0);
170fdfb7f2cSAlexander Graf     gchar *group = g_strdup_printf("%s/queue-group", node);
171fdfb7f2cSAlexander Graf     void *fdt = data->fdt;
172fdfb7f2cSAlexander Graf 
173fdfb7f2cSAlexander Graf     assert((int64_t)mmio0 >= 0);
174fdfb7f2cSAlexander Graf     assert(irq0 >= 0);
175fdfb7f2cSAlexander Graf     assert(irq1 >= 0);
176fdfb7f2cSAlexander Graf     assert(irq2 >= 0);
177fdfb7f2cSAlexander Graf 
178fdfb7f2cSAlexander Graf     qemu_fdt_add_subnode(fdt, node);
179fdfb7f2cSAlexander Graf     qemu_fdt_setprop_string(fdt, node, "device_type", "network");
180fdfb7f2cSAlexander Graf     qemu_fdt_setprop_string(fdt, node, "compatible", "fsl,etsec2");
181fdfb7f2cSAlexander Graf     qemu_fdt_setprop_string(fdt, node, "model", "eTSEC");
182fdfb7f2cSAlexander Graf     qemu_fdt_setprop(fdt, node, "local-mac-address", etsec->conf.macaddr.a, 6);
183fdfb7f2cSAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "fixed-link", 0, 1, 1000, 0, 0);
184fdfb7f2cSAlexander Graf 
185fdfb7f2cSAlexander Graf     qemu_fdt_add_subnode(fdt, group);
186fdfb7f2cSAlexander Graf     qemu_fdt_setprop_cells(fdt, group, "reg", mmio0, 0x1000);
187fdfb7f2cSAlexander Graf     qemu_fdt_setprop_cells(fdt, group, "interrupts",
188fdfb7f2cSAlexander Graf         data->irq_start + irq0, 0x2,
189fdfb7f2cSAlexander Graf         data->irq_start + irq1, 0x2,
190fdfb7f2cSAlexander Graf         data->irq_start + irq2, 0x2);
191fdfb7f2cSAlexander Graf 
192fdfb7f2cSAlexander Graf     g_free(node);
193fdfb7f2cSAlexander Graf     g_free(group);
194fdfb7f2cSAlexander Graf 
195fdfb7f2cSAlexander Graf     return 0;
196fdfb7f2cSAlexander Graf }
197fdfb7f2cSAlexander Graf 
198f7087343SAlexander Graf static int sysbus_device_create_devtree(SysBusDevice *sbdev, void *opaque)
199f7087343SAlexander Graf {
200f7087343SAlexander Graf     PlatformDevtreeData *data = opaque;
201f7087343SAlexander Graf     bool matched = false;
202f7087343SAlexander Graf 
203fdfb7f2cSAlexander Graf     if (object_dynamic_cast(OBJECT(sbdev), TYPE_ETSEC_COMMON)) {
204fdfb7f2cSAlexander Graf         create_devtree_etsec(sbdev, data);
205fdfb7f2cSAlexander Graf         matched = true;
206fdfb7f2cSAlexander Graf     }
207fdfb7f2cSAlexander Graf 
208f7087343SAlexander Graf     if (!matched) {
209f7087343SAlexander Graf         error_report("Device %s is not supported by this machine yet.",
210f7087343SAlexander Graf                      qdev_fw_name(DEVICE(sbdev)));
211f7087343SAlexander Graf         exit(1);
212f7087343SAlexander Graf     }
213f7087343SAlexander Graf 
214f7087343SAlexander Graf     return 0;
215f7087343SAlexander Graf }
216f7087343SAlexander Graf 
217f7087343SAlexander Graf static void platform_bus_create_devtree(PPCE500Params *params, void *fdt,
218f7087343SAlexander Graf                                         const char *mpic)
219f7087343SAlexander Graf {
220f7087343SAlexander Graf     gchar *node = g_strdup_printf("/platform@%"PRIx64, params->platform_bus_base);
221f7087343SAlexander Graf     const char platcomp[] = "qemu,platform\0simple-bus";
222f7087343SAlexander Graf     uint64_t addr = params->platform_bus_base;
223f7087343SAlexander Graf     uint64_t size = params->platform_bus_size;
224f7087343SAlexander Graf     int irq_start = params->platform_bus_first_irq;
225f7087343SAlexander Graf     PlatformBusDevice *pbus;
226f7087343SAlexander Graf     DeviceState *dev;
227f7087343SAlexander Graf 
228f7087343SAlexander Graf     /* Create a /platform node that we can put all devices into */
229f7087343SAlexander Graf 
230f7087343SAlexander Graf     qemu_fdt_add_subnode(fdt, node);
231f7087343SAlexander Graf     qemu_fdt_setprop(fdt, node, "compatible", platcomp, sizeof(platcomp));
232f7087343SAlexander Graf 
233f7087343SAlexander Graf     /* Our platform bus region is less than 32bit big, so 1 cell is enough for
234f7087343SAlexander Graf        address and size */
235f7087343SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "#size-cells", 1);
236f7087343SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "#address-cells", 1);
237f7087343SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "ranges", 0, addr >> 32, addr, size);
238f7087343SAlexander Graf 
239f7087343SAlexander Graf     qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", mpic);
240f7087343SAlexander Graf 
241f7087343SAlexander Graf     dev = qdev_find_recursive(sysbus_get_default(), TYPE_PLATFORM_BUS_DEVICE);
242f7087343SAlexander Graf     pbus = PLATFORM_BUS_DEVICE(dev);
243f7087343SAlexander Graf 
244f7087343SAlexander Graf     /* We can only create dt nodes for dynamic devices when they're ready */
245f7087343SAlexander Graf     if (pbus->done_gathering) {
246f7087343SAlexander Graf         PlatformDevtreeData data = {
247f7087343SAlexander Graf             .fdt = fdt,
248f7087343SAlexander Graf             .mpic = mpic,
249f7087343SAlexander Graf             .irq_start = irq_start,
250f7087343SAlexander Graf             .node = node,
251f7087343SAlexander Graf             .pbus = pbus,
252f7087343SAlexander Graf         };
253f7087343SAlexander Graf 
254f7087343SAlexander Graf         /* Loop through all dynamic sysbus devices and create nodes for them */
255f7087343SAlexander Graf         foreach_dynamic_sysbus_device(sysbus_device_create_devtree, &data);
256f7087343SAlexander Graf     }
257f7087343SAlexander Graf 
258f7087343SAlexander Graf     g_free(node);
259f7087343SAlexander Graf }
260f7087343SAlexander Graf 
2613ef96221SMarcel Apfelbaum static int ppce500_load_device_tree(MachineState *machine,
262e6eaabebSScott Wood                                     PPCE500Params *params,
263a8170e5eSAvi Kivity                                     hwaddr addr,
264a8170e5eSAvi Kivity                                     hwaddr initrd_base,
26528290f37SAlexander Graf                                     hwaddr initrd_size,
266903585deSAlexander Graf                                     hwaddr kernel_base,
267903585deSAlexander Graf                                     hwaddr kernel_size,
26828290f37SAlexander Graf                                     bool dry_run)
2691db09b84Saurel32 {
27028290f37SAlexander Graf     CPUPPCState *env = first_cpu->env_ptr;
271dbf916d8SAurelien Jarno     int ret = -1;
2723ef96221SMarcel Apfelbaum     uint64_t mem_reg_property[] = { 0, cpu_to_be64(machine->ram_size) };
2737ec632b4Spbrook     int fdt_size;
274dbf916d8SAurelien Jarno     void *fdt;
2755de6b46dSAlexander Graf     uint8_t hypercall[16];
276911d6e7aSAlexander Graf     uint32_t clock_freq = 400000000;
277911d6e7aSAlexander Graf     uint32_t tb_freq = 400000000;
278621d05e3SAlexander Graf     int i;
279ebb9518aSAlexander Graf     char compatible_sb[] = "fsl,mpc8544-immr\0simple-bus";
2805da96624SAlexander Graf     char soc[128];
28119ac9deaSAlexander Graf     char mpic[128];
28219ac9deaSAlexander Graf     uint32_t mpic_ph;
283a911b7a9SAlexander Graf     uint32_t msi_ph;
284f5038483SAlexander Graf     char gutil[128];
2850dbc0798SAlexander Graf     char pci[128];
286a911b7a9SAlexander Graf     char msi[128];
287347dd79dSAlexander Graf     uint32_t *pci_map = NULL;
288347dd79dSAlexander Graf     int len;
2893627757eSAlexander Graf     uint32_t pci_ranges[14] =
2903627757eSAlexander Graf         {
291cb3778a0SAlexander Graf             0x2000000, 0x0, params->pci_mmio_bus_base,
292cb3778a0SAlexander Graf             params->pci_mmio_base >> 32, params->pci_mmio_base,
2933627757eSAlexander Graf             0x0, 0x20000000,
2943627757eSAlexander Graf 
2953627757eSAlexander Graf             0x1000000, 0x0, 0x0,
2962eaaac1fSAlexander Graf             params->pci_pio_base >> 32, params->pci_pio_base,
2973627757eSAlexander Graf             0x0, 0x10000,
2983627757eSAlexander Graf         };
2992ff3de68SMarkus Armbruster     QemuOpts *machine_opts = qemu_get_machine_opts();
3002ff3de68SMarkus Armbruster     const char *dtb_file = qemu_opt_get(machine_opts, "dtb");
3012ff3de68SMarkus Armbruster     const char *toplevel_compat = qemu_opt_get(machine_opts, "dt_compatible");
302d1b93565SAlexander Graf 
303d1b93565SAlexander Graf     if (dtb_file) {
304d1b93565SAlexander Graf         char *filename;
305d1b93565SAlexander Graf         filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_file);
306d1b93565SAlexander Graf         if (!filename) {
307d1b93565SAlexander Graf             goto out;
308d1b93565SAlexander Graf         }
309d1b93565SAlexander Graf 
310d1b93565SAlexander Graf         fdt = load_device_tree(filename, &fdt_size);
3112343dd11SMichael Tokarev         g_free(filename);
312d1b93565SAlexander Graf         if (!fdt) {
313d1b93565SAlexander Graf             goto out;
314d1b93565SAlexander Graf         }
315d1b93565SAlexander Graf         goto done;
316d1b93565SAlexander Graf     }
3171db09b84Saurel32 
3182636fcb6SAlexander Graf     fdt = create_device_tree(&fdt_size);
3195cea8590SPaul Brook     if (fdt == NULL) {
3205cea8590SPaul Brook         goto out;
3215cea8590SPaul Brook     }
3221db09b84Saurel32 
3231db09b84Saurel32     /* Manipulate device tree in memory. */
3245a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 2);
3255a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 2);
32651b852b7SAlexander Graf 
3275a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, "/memory");
3285a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, "/memory", "device_type", "memory");
3295a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, "/memory", "reg", mem_reg_property,
3301db09b84Saurel32                      sizeof(mem_reg_property));
3311db09b84Saurel32 
3325a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, "/chosen");
3333b989d49SAlexander Graf     if (initrd_size) {
3345a4348d1SPeter Crosthwaite         ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start",
3351db09b84Saurel32                                     initrd_base);
3363b989d49SAlexander Graf         if (ret < 0) {
3371db09b84Saurel32             fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
3383b989d49SAlexander Graf         }
3391db09b84Saurel32 
3405a4348d1SPeter Crosthwaite         ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
3411db09b84Saurel32                                     (initrd_base + initrd_size));
3423b989d49SAlexander Graf         if (ret < 0) {
3431db09b84Saurel32             fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
3443b989d49SAlexander Graf         }
345903585deSAlexander Graf 
346903585deSAlexander Graf     }
347903585deSAlexander Graf 
348903585deSAlexander Graf     if (kernel_base != -1ULL) {
349903585deSAlexander Graf         qemu_fdt_setprop_cells(fdt, "/chosen", "qemu,boot-kernel",
350903585deSAlexander Graf                                      kernel_base >> 32, kernel_base,
351903585deSAlexander Graf                                      kernel_size >> 32, kernel_size);
3523b989d49SAlexander Graf     }
3531db09b84Saurel32 
3545a4348d1SPeter Crosthwaite     ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
3553ef96221SMarcel Apfelbaum                                       machine->kernel_cmdline);
3561db09b84Saurel32     if (ret < 0)
3571db09b84Saurel32         fprintf(stderr, "couldn't set /chosen/bootargs\n");
3581db09b84Saurel32 
3591db09b84Saurel32     if (kvm_enabled()) {
360911d6e7aSAlexander Graf         /* Read out host's frequencies */
361911d6e7aSAlexander Graf         clock_freq = kvmppc_get_clockfreq();
362911d6e7aSAlexander Graf         tb_freq = kvmppc_get_tbfreq();
3635de6b46dSAlexander Graf 
3645de6b46dSAlexander Graf         /* indicate KVM hypercall interface */
3655a4348d1SPeter Crosthwaite         qemu_fdt_add_subnode(fdt, "/hypervisor");
3665a4348d1SPeter Crosthwaite         qemu_fdt_setprop_string(fdt, "/hypervisor", "compatible",
3675de6b46dSAlexander Graf                                 "linux,kvm");
3685de6b46dSAlexander Graf         kvmppc_get_hypercall(env, hypercall, sizeof(hypercall));
3695a4348d1SPeter Crosthwaite         qemu_fdt_setprop(fdt, "/hypervisor", "hcall-instructions",
3705de6b46dSAlexander Graf                          hypercall, sizeof(hypercall));
3711a61a9aeSStuart Yoder         /* if KVM supports the idle hcall, set property indicating this */
3721a61a9aeSStuart Yoder         if (kvmppc_get_hasidle(env)) {
3735a4348d1SPeter Crosthwaite             qemu_fdt_setprop(fdt, "/hypervisor", "has-idle", NULL, 0);
3741a61a9aeSStuart Yoder         }
3751db09b84Saurel32     }
3761db09b84Saurel32 
377625e665bSAlexander Graf     /* Create CPU nodes */
3785a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, "/cpus");
3795a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 1);
3805a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0);
381625e665bSAlexander Graf 
3821e3debf0SAlexander Graf     /* We need to generate the cpu nodes in reverse order, so Linux can pick
3831e3debf0SAlexander Graf        the first node as boot node and be happy */
3841e3debf0SAlexander Graf     for (i = smp_cpus - 1; i >= 0; i--) {
385440c8152SAndreas Färber         CPUState *cpu;
3860f20ba62SAlexey Kardashevskiy         PowerPCCPU *pcpu;
387621d05e3SAlexander Graf         char cpu_name[128];
3882eaaac1fSAlexander Graf         uint64_t cpu_release_addr = params->spin_base + (i * 0x20);
38910f25a46SAlexander Graf 
390440c8152SAndreas Färber         cpu = qemu_get_cpu(i);
39155e5c285SAndreas Färber         if (cpu == NULL) {
3921e3debf0SAlexander Graf             continue;
3931e3debf0SAlexander Graf         }
394440c8152SAndreas Färber         env = cpu->env_ptr;
3950f20ba62SAlexey Kardashevskiy         pcpu = POWERPC_CPU(cpu);
3961e3debf0SAlexander Graf 
39755e5c285SAndreas Färber         snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x",
3980f20ba62SAlexey Kardashevskiy                  ppc_get_vcpu_dt_id(pcpu));
3995a4348d1SPeter Crosthwaite         qemu_fdt_add_subnode(fdt, cpu_name);
4005a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq);
4015a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq);
4025a4348d1SPeter Crosthwaite         qemu_fdt_setprop_string(fdt, cpu_name, "device_type", "cpu");
4030f20ba62SAlexey Kardashevskiy         qemu_fdt_setprop_cell(fdt, cpu_name, "reg",
4040f20ba62SAlexey Kardashevskiy                               ppc_get_vcpu_dt_id(pcpu));
4055a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-line-size",
4061e3debf0SAlexander Graf                               env->dcache_line_size);
4075a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-line-size",
4081e3debf0SAlexander Graf                               env->icache_line_size);
4095a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-size", 0x8000);
4105a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-size", 0x8000);
4115a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "bus-frequency", 0);
41255e5c285SAndreas Färber         if (cpu->cpu_index) {
4135a4348d1SPeter Crosthwaite             qemu_fdt_setprop_string(fdt, cpu_name, "status", "disabled");
4145a4348d1SPeter Crosthwaite             qemu_fdt_setprop_string(fdt, cpu_name, "enable-method",
4155a4348d1SPeter Crosthwaite                                     "spin-table");
4165a4348d1SPeter Crosthwaite             qemu_fdt_setprop_u64(fdt, cpu_name, "cpu-release-addr",
4171d2e5c52SAlexander Graf                                  cpu_release_addr);
4181e3debf0SAlexander Graf         } else {
4195a4348d1SPeter Crosthwaite             qemu_fdt_setprop_string(fdt, cpu_name, "status", "okay");
4201e3debf0SAlexander Graf         }
4211db09b84Saurel32     }
4221db09b84Saurel32 
4235a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, "/aliases");
4245da96624SAlexander Graf     /* XXX These should go into their respective devices' code */
4252eaaac1fSAlexander Graf     snprintf(soc, sizeof(soc), "/soc@%"PRIx64, params->ccsrbar_base);
4265a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, soc);
4275a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, soc, "device_type", "soc");
4285a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, soc, "compatible", compatible_sb,
429ebb9518aSAlexander Graf                      sizeof(compatible_sb));
4305a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, soc, "#address-cells", 1);
4315a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, soc, "#size-cells", 1);
4325a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, soc, "ranges", 0x0,
4332eaaac1fSAlexander Graf                            params->ccsrbar_base >> 32, params->ccsrbar_base,
4345da96624SAlexander Graf                            MPC8544_CCSRBAR_SIZE);
4355da96624SAlexander Graf     /* XXX should contain a reasonable value */
4365a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, soc, "bus-frequency", 0);
4375da96624SAlexander Graf 
438dffb1dc2SBharat Bhushan     snprintf(mpic, sizeof(mpic), "%s/pic@%llx", soc, MPC8544_MPIC_REGS_OFFSET);
4395a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, mpic);
4405a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, mpic, "device_type", "open-pic");
4415a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, mpic, "compatible", "fsl,mpic");
4425a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_OFFSET,
443dffb1dc2SBharat Bhushan                            0x40000);
4445a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, mpic, "#address-cells", 0);
4455a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, mpic, "#interrupt-cells", 2);
4465a4348d1SPeter Crosthwaite     mpic_ph = qemu_fdt_alloc_phandle(fdt);
4475a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, mpic, "phandle", mpic_ph);
4485a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, mpic, "linux,phandle", mpic_ph);
4495a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, mpic, "interrupt-controller", NULL, 0);
45019ac9deaSAlexander Graf 
4510cfc6e8dSAlexander Graf     /*
4520cfc6e8dSAlexander Graf      * We have to generate ser1 first, because Linux takes the first
4530cfc6e8dSAlexander Graf      * device it finds in the dt as serial output device. And we generate
4540cfc6e8dSAlexander Graf      * devices in reverse order to the dt.
4550cfc6e8dSAlexander Graf      */
45679c0ff2cSAlexander Graf     if (serial_hds[1]) {
457dffb1dc2SBharat Bhushan         dt_serial_create(fdt, MPC8544_SERIAL1_REGS_OFFSET,
458a053a7ceSAlexander Graf                          soc, mpic, "serial1", 1, false);
45979c0ff2cSAlexander Graf     }
46079c0ff2cSAlexander Graf 
46179c0ff2cSAlexander Graf     if (serial_hds[0]) {
462dffb1dc2SBharat Bhushan         dt_serial_create(fdt, MPC8544_SERIAL0_REGS_OFFSET,
463a053a7ceSAlexander Graf                          soc, mpic, "serial0", 0, true);
46479c0ff2cSAlexander Graf     }
4650cfc6e8dSAlexander Graf 
466ed2bc496SAlexander Graf     snprintf(gutil, sizeof(gutil), "%s/global-utilities@%llx", soc,
467dffb1dc2SBharat Bhushan              MPC8544_UTIL_OFFSET);
4685a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, gutil);
4695a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, gutil, "compatible", "fsl,mpc8544-guts");
4705a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, gutil, "reg", MPC8544_UTIL_OFFSET, 0x1000);
4715a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, gutil, "fsl,has-rstcr", NULL, 0);
472f5038483SAlexander Graf 
473a911b7a9SAlexander Graf     snprintf(msi, sizeof(msi), "/%s/msi@%llx", soc, MPC8544_MSI_REGS_OFFSET);
4745a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, msi);
4755a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, msi, "compatible", "fsl,mpic-msi");
4765a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, msi, "reg", MPC8544_MSI_REGS_OFFSET, 0x200);
4775a4348d1SPeter Crosthwaite     msi_ph = qemu_fdt_alloc_phandle(fdt);
4785a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, msi, "msi-available-ranges", 0x0, 0x100);
4795a4348d1SPeter Crosthwaite     qemu_fdt_setprop_phandle(fdt, msi, "interrupt-parent", mpic);
4805a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, msi, "interrupts",
481a911b7a9SAlexander Graf         0xe0, 0x0,
482a911b7a9SAlexander Graf         0xe1, 0x0,
483a911b7a9SAlexander Graf         0xe2, 0x0,
484a911b7a9SAlexander Graf         0xe3, 0x0,
485a911b7a9SAlexander Graf         0xe4, 0x0,
486a911b7a9SAlexander Graf         0xe5, 0x0,
487a911b7a9SAlexander Graf         0xe6, 0x0,
488a911b7a9SAlexander Graf         0xe7, 0x0);
4895a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, msi, "phandle", msi_ph);
4905a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, msi, "linux,phandle", msi_ph);
491a911b7a9SAlexander Graf 
4922eaaac1fSAlexander Graf     snprintf(pci, sizeof(pci), "/pci@%llx",
4932eaaac1fSAlexander Graf              params->ccsrbar_base + MPC8544_PCI_REGS_OFFSET);
4945a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, pci);
4955a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "cell-index", 0);
4965a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, pci, "compatible", "fsl,mpc8540-pci");
4975a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, pci, "device_type", "pci");
4985a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, pci, "interrupt-map-mask", 0xf800, 0x0,
4990dbc0798SAlexander Graf                            0x0, 0x7);
5005a4348d1SPeter Crosthwaite     pci_map = pci_map_create(fdt, qemu_fdt_get_phandle(fdt, mpic),
501492ec48dSAlexander Graf                              params->pci_first_slot, params->pci_nr_slots,
502492ec48dSAlexander Graf                              &len);
5035a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, pci, "interrupt-map", pci_map, len);
5045a4348d1SPeter Crosthwaite     qemu_fdt_setprop_phandle(fdt, pci, "interrupt-parent", mpic);
5055a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, pci, "interrupts", 24, 2);
5065a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, pci, "bus-range", 0, 255);
5073627757eSAlexander Graf     for (i = 0; i < 14; i++) {
5080dbc0798SAlexander Graf         pci_ranges[i] = cpu_to_be32(pci_ranges[i]);
5090dbc0798SAlexander Graf     }
5105a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "fsl,msi", msi_ph);
5115a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, pci, "ranges", pci_ranges, sizeof(pci_ranges));
5122eaaac1fSAlexander Graf     qemu_fdt_setprop_cells(fdt, pci, "reg",
5132eaaac1fSAlexander Graf                            (params->ccsrbar_base + MPC8544_PCI_REGS_OFFSET) >> 32,
5142eaaac1fSAlexander Graf                            (params->ccsrbar_base + MPC8544_PCI_REGS_OFFSET),
5152eaaac1fSAlexander Graf                            0, 0x1000);
5165a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "clock-frequency", 66666666);
5175a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "#interrupt-cells", 1);
5185a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "#size-cells", 2);
5195a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "#address-cells", 3);
5205a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, "/aliases", "pci0", pci);
5210dbc0798SAlexander Graf 
522b88e77f4SAlexander Graf     if (params->has_mpc8xxx_gpio) {
523b88e77f4SAlexander Graf         create_dt_mpc8xxx_gpio(fdt, soc, mpic);
524b88e77f4SAlexander Graf     }
525b88e77f4SAlexander Graf 
526f7087343SAlexander Graf     if (params->has_platform_bus) {
527f7087343SAlexander Graf         platform_bus_create_devtree(params, fdt, mpic);
528f7087343SAlexander Graf     }
529f7087343SAlexander Graf 
530e6eaabebSScott Wood     params->fixup_devtree(params, fdt);
531e6eaabebSScott Wood 
532e6eaabebSScott Wood     if (toplevel_compat) {
5335a4348d1SPeter Crosthwaite         qemu_fdt_setprop(fdt, "/", "compatible", toplevel_compat,
534e6eaabebSScott Wood                          strlen(toplevel_compat) + 1);
535e6eaabebSScott Wood     }
536e6eaabebSScott Wood 
537d1b93565SAlexander Graf done:
53828290f37SAlexander Graf     if (!dry_run) {
5395a4348d1SPeter Crosthwaite         qemu_fdt_dumpdtb(fdt, fdt_size);
54028290f37SAlexander Graf         cpu_physical_memory_write(addr, fdt, fdt_size);
541cba2026aSAlexander Graf     }
542cba2026aSAlexander Graf     ret = fdt_size;
5437ec632b4Spbrook 
5441db09b84Saurel32 out:
545347dd79dSAlexander Graf     g_free(pci_map);
5461db09b84Saurel32 
54704088adbSLiu Yu     return ret;
5481db09b84Saurel32 }
5491db09b84Saurel32 
55028290f37SAlexander Graf typedef struct DeviceTreeParams {
5513ef96221SMarcel Apfelbaum     MachineState *machine;
55228290f37SAlexander Graf     PPCE500Params params;
55328290f37SAlexander Graf     hwaddr addr;
55428290f37SAlexander Graf     hwaddr initrd_base;
55528290f37SAlexander Graf     hwaddr initrd_size;
556903585deSAlexander Graf     hwaddr kernel_base;
557903585deSAlexander Graf     hwaddr kernel_size;
558f7087343SAlexander Graf     Notifier notifier;
55928290f37SAlexander Graf } DeviceTreeParams;
56028290f37SAlexander Graf 
56128290f37SAlexander Graf static void ppce500_reset_device_tree(void *opaque)
56228290f37SAlexander Graf {
56328290f37SAlexander Graf     DeviceTreeParams *p = opaque;
5643812c71fSAlexander Graf     ppce500_load_device_tree(p->machine, &p->params, p->addr, p->initrd_base,
565903585deSAlexander Graf                              p->initrd_size, p->kernel_base, p->kernel_size,
566903585deSAlexander Graf                              false);
56728290f37SAlexander Graf }
56828290f37SAlexander Graf 
569f7087343SAlexander Graf static void ppce500_init_notify(Notifier *notifier, void *data)
570f7087343SAlexander Graf {
571f7087343SAlexander Graf     DeviceTreeParams *p = container_of(notifier, DeviceTreeParams, notifier);
572f7087343SAlexander Graf     ppce500_reset_device_tree(p);
573f7087343SAlexander Graf }
574f7087343SAlexander Graf 
5753ef96221SMarcel Apfelbaum static int ppce500_prep_device_tree(MachineState *machine,
57628290f37SAlexander Graf                                     PPCE500Params *params,
57728290f37SAlexander Graf                                     hwaddr addr,
57828290f37SAlexander Graf                                     hwaddr initrd_base,
579903585deSAlexander Graf                                     hwaddr initrd_size,
580903585deSAlexander Graf                                     hwaddr kernel_base,
581903585deSAlexander Graf                                     hwaddr kernel_size)
58228290f37SAlexander Graf {
58328290f37SAlexander Graf     DeviceTreeParams *p = g_new(DeviceTreeParams, 1);
5843ef96221SMarcel Apfelbaum     p->machine = machine;
58528290f37SAlexander Graf     p->params = *params;
58628290f37SAlexander Graf     p->addr = addr;
58728290f37SAlexander Graf     p->initrd_base = initrd_base;
58828290f37SAlexander Graf     p->initrd_size = initrd_size;
589903585deSAlexander Graf     p->kernel_base = kernel_base;
590903585deSAlexander Graf     p->kernel_size = kernel_size;
59128290f37SAlexander Graf 
59228290f37SAlexander Graf     qemu_register_reset(ppce500_reset_device_tree, p);
593f7087343SAlexander Graf     p->notifier.notify = ppce500_init_notify;
594f7087343SAlexander Graf     qemu_add_machine_init_done_notifier(&p->notifier);
59528290f37SAlexander Graf 
59628290f37SAlexander Graf     /* Issue the device tree loader once, so that we get the size of the blob */
5973ef96221SMarcel Apfelbaum     return ppce500_load_device_tree(machine, params, addr, initrd_base,
598903585deSAlexander Graf                                     initrd_size, kernel_base, kernel_size,
599903585deSAlexander Graf                                     true);
60028290f37SAlexander Graf }
60128290f37SAlexander Graf 
602cba2026aSAlexander Graf /* Create -kernel TLB entries for BookE.  */
603a8170e5eSAvi Kivity static inline hwaddr booke206_page_size_to_tlb(uint64_t size)
604d1e256feSAlexander Graf {
605cba2026aSAlexander Graf     return 63 - clz64(size >> 10);
606d1e256feSAlexander Graf }
607d1e256feSAlexander Graf 
608cefd3cdbSBharat Bhushan static int booke206_initial_map_tsize(CPUPPCState *env)
6093b989d49SAlexander Graf {
610cba2026aSAlexander Graf     struct boot_info *bi = env->load_info;
611cefd3cdbSBharat Bhushan     hwaddr dt_end;
612cba2026aSAlexander Graf     int ps;
6133b989d49SAlexander Graf 
614cba2026aSAlexander Graf     /* Our initial TLB entry needs to cover everything from 0 to
615cba2026aSAlexander Graf        the device tree top */
616cba2026aSAlexander Graf     dt_end = bi->dt_base + bi->dt_size;
617cba2026aSAlexander Graf     ps = booke206_page_size_to_tlb(dt_end) + 1;
618fb37c302SAlexander Graf     if (ps & 1) {
619fb37c302SAlexander Graf         /* e500v2 can only do even TLB size bits */
620fb37c302SAlexander Graf         ps++;
621fb37c302SAlexander Graf     }
622cefd3cdbSBharat Bhushan     return ps;
623cefd3cdbSBharat Bhushan }
624cefd3cdbSBharat Bhushan 
625cefd3cdbSBharat Bhushan static uint64_t mmubooke_initial_mapsize(CPUPPCState *env)
626cefd3cdbSBharat Bhushan {
627cefd3cdbSBharat Bhushan     int tsize;
628cefd3cdbSBharat Bhushan 
629cefd3cdbSBharat Bhushan     tsize = booke206_initial_map_tsize(env);
630cefd3cdbSBharat Bhushan     return (1ULL << 10 << tsize);
631cefd3cdbSBharat Bhushan }
632cefd3cdbSBharat Bhushan 
633cefd3cdbSBharat Bhushan static void mmubooke_create_initial_mapping(CPUPPCState *env)
634cefd3cdbSBharat Bhushan {
635cefd3cdbSBharat Bhushan     ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0);
636cefd3cdbSBharat Bhushan     hwaddr size;
637cefd3cdbSBharat Bhushan     int ps;
638cefd3cdbSBharat Bhushan 
639cefd3cdbSBharat Bhushan     ps = booke206_initial_map_tsize(env);
640cba2026aSAlexander Graf     size = (ps << MAS1_TSIZE_SHIFT);
641d1e256feSAlexander Graf     tlb->mas1 = MAS1_VALID | size;
642cba2026aSAlexander Graf     tlb->mas2 = 0;
643cba2026aSAlexander Graf     tlb->mas7_3 = 0;
644d1e256feSAlexander Graf     tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
64593dd5e85SScott Wood 
64693dd5e85SScott Wood     env->tlb_dirty = true;
6473b989d49SAlexander Graf }
6483b989d49SAlexander Graf 
649b3305981SScott Wood static void ppce500_cpu_reset_sec(void *opaque)
6505c145dacSAlexander Graf {
65138f92da6SAndreas Färber     PowerPCCPU *cpu = opaque;
652259186a7SAndreas Färber     CPUState *cs = CPU(cpu);
6535c145dacSAlexander Graf 
654259186a7SAndreas Färber     cpu_reset(cs);
6555c145dacSAlexander Graf 
6565c145dacSAlexander Graf     /* Secondary CPU starts in halted state for now. Needs to change when
6575c145dacSAlexander Graf        implementing non-kernel boot. */
658259186a7SAndreas Färber     cs->halted = 1;
65927103424SAndreas Färber     cs->exception_index = EXCP_HLT;
6603b989d49SAlexander Graf }
6613b989d49SAlexander Graf 
662b3305981SScott Wood static void ppce500_cpu_reset(void *opaque)
6633b989d49SAlexander Graf {
66438f92da6SAndreas Färber     PowerPCCPU *cpu = opaque;
665259186a7SAndreas Färber     CPUState *cs = CPU(cpu);
66638f92da6SAndreas Färber     CPUPPCState *env = &cpu->env;
6673b989d49SAlexander Graf     struct boot_info *bi = env->load_info;
6683b989d49SAlexander Graf 
669259186a7SAndreas Färber     cpu_reset(cs);
6703b989d49SAlexander Graf 
6713b989d49SAlexander Graf     /* Set initial guest state. */
672259186a7SAndreas Färber     cs->halted = 0;
6733b989d49SAlexander Graf     env->gpr[1] = (16<<20) - 8;
6743b989d49SAlexander Graf     env->gpr[3] = bi->dt_base;
675cefd3cdbSBharat Bhushan     env->gpr[4] = 0;
676cefd3cdbSBharat Bhushan     env->gpr[5] = 0;
677cefd3cdbSBharat Bhushan     env->gpr[6] = EPAPR_MAGIC;
678cefd3cdbSBharat Bhushan     env->gpr[7] = mmubooke_initial_mapsize(env);
679cefd3cdbSBharat Bhushan     env->gpr[8] = 0;
680cefd3cdbSBharat Bhushan     env->gpr[9] = 0;
6813b989d49SAlexander Graf     env->nip = bi->entry;
682cba2026aSAlexander Graf     mmubooke_create_initial_mapping(env);
6833b989d49SAlexander Graf }
6843b989d49SAlexander Graf 
685d85937e6SScott Wood static DeviceState *ppce500_init_mpic_qemu(PPCE500Params *params,
68682fc73b6SScott Wood                                            qemu_irq **irqs)
68782fc73b6SScott Wood {
68882fc73b6SScott Wood     DeviceState *dev;
68982fc73b6SScott Wood     SysBusDevice *s;
69082fc73b6SScott Wood     int i, j, k;
69182fc73b6SScott Wood 
692e1766344SAndreas Färber     dev = qdev_create(NULL, TYPE_OPENPIC);
69382fc73b6SScott Wood     qdev_prop_set_uint32(dev, "model", params->mpic_version);
694d85937e6SScott Wood     qdev_prop_set_uint32(dev, "nb_cpus", smp_cpus);
695d85937e6SScott Wood 
69682fc73b6SScott Wood     qdev_init_nofail(dev);
69782fc73b6SScott Wood     s = SYS_BUS_DEVICE(dev);
69882fc73b6SScott Wood 
69982fc73b6SScott Wood     k = 0;
70082fc73b6SScott Wood     for (i = 0; i < smp_cpus; i++) {
70182fc73b6SScott Wood         for (j = 0; j < OPENPIC_OUTPUT_NB; j++) {
70282fc73b6SScott Wood             sysbus_connect_irq(s, k++, irqs[i][j]);
70382fc73b6SScott Wood         }
70482fc73b6SScott Wood     }
70582fc73b6SScott Wood 
706d85937e6SScott Wood     return dev;
707d85937e6SScott Wood }
708d85937e6SScott Wood 
709d85937e6SScott Wood static DeviceState *ppce500_init_mpic_kvm(PPCE500Params *params,
710fe656ebdSMarkus Armbruster                                           qemu_irq **irqs, Error **errp)
711d85937e6SScott Wood {
712fe656ebdSMarkus Armbruster     Error *err = NULL;
713d85937e6SScott Wood     DeviceState *dev;
714d85937e6SScott Wood     CPUState *cs;
715d85937e6SScott Wood 
716dd49c038SAndreas Färber     dev = qdev_create(NULL, TYPE_KVM_OPENPIC);
717d85937e6SScott Wood     qdev_prop_set_uint32(dev, "model", params->mpic_version);
718d85937e6SScott Wood 
719fe656ebdSMarkus Armbruster     object_property_set_bool(OBJECT(dev), true, "realized", &err);
720fe656ebdSMarkus Armbruster     if (err) {
721fe656ebdSMarkus Armbruster         error_propagate(errp, err);
722fe656ebdSMarkus Armbruster         object_unparent(OBJECT(dev));
723d85937e6SScott Wood         return NULL;
724d85937e6SScott Wood     }
725d85937e6SScott Wood 
726bdc44640SAndreas Färber     CPU_FOREACH(cs) {
727d85937e6SScott Wood         if (kvm_openpic_connect_vcpu(dev, cs)) {
728d85937e6SScott Wood             fprintf(stderr, "%s: failed to connect vcpu to irqchip\n",
729d85937e6SScott Wood                     __func__);
730d85937e6SScott Wood             abort();
731d85937e6SScott Wood         }
732d85937e6SScott Wood     }
733d85937e6SScott Wood 
734d85937e6SScott Wood     return dev;
735d85937e6SScott Wood }
736d85937e6SScott Wood 
737446f16a6SMarcel Apfelbaum static qemu_irq *ppce500_init_mpic(MachineState *machine, PPCE500Params *params,
738446f16a6SMarcel Apfelbaum                                    MemoryRegion *ccsr, qemu_irq **irqs)
739d85937e6SScott Wood {
740d85937e6SScott Wood     qemu_irq *mpic;
741d85937e6SScott Wood     DeviceState *dev = NULL;
742d85937e6SScott Wood     SysBusDevice *s;
743d85937e6SScott Wood     int i;
744d85937e6SScott Wood 
745aa2ac1daSPeter Crosthwaite     mpic = g_new0(qemu_irq, 256);
746d85937e6SScott Wood 
747d85937e6SScott Wood     if (kvm_enabled()) {
748fe656ebdSMarkus Armbruster         Error *err = NULL;
749d85937e6SScott Wood 
750446f16a6SMarcel Apfelbaum         if (machine_kernel_irqchip_allowed(machine)) {
751fe656ebdSMarkus Armbruster             dev = ppce500_init_mpic_kvm(params, irqs, &err);
752d85937e6SScott Wood         }
753446f16a6SMarcel Apfelbaum         if (machine_kernel_irqchip_required(machine) && !dev) {
754*c29b77f9SMarkus Armbruster             error_reportf_err(err,
755*c29b77f9SMarkus Armbruster                               "kernel_irqchip requested but unavailable: ");
756fe656ebdSMarkus Armbruster             exit(1);
757d85937e6SScott Wood         }
758d85937e6SScott Wood     }
759d85937e6SScott Wood 
760d85937e6SScott Wood     if (!dev) {
761d85937e6SScott Wood         dev = ppce500_init_mpic_qemu(params, irqs);
762d85937e6SScott Wood     }
763d85937e6SScott Wood 
76482fc73b6SScott Wood     for (i = 0; i < 256; i++) {
76582fc73b6SScott Wood         mpic[i] = qdev_get_gpio_in(dev, i);
76682fc73b6SScott Wood     }
76782fc73b6SScott Wood 
768d85937e6SScott Wood     s = SYS_BUS_DEVICE(dev);
76982fc73b6SScott Wood     memory_region_add_subregion(ccsr, MPC8544_MPIC_REGS_OFFSET,
77082fc73b6SScott Wood                                 s->mmio[0].memory);
77182fc73b6SScott Wood 
77282fc73b6SScott Wood     return mpic;
77382fc73b6SScott Wood }
77482fc73b6SScott Wood 
775016f7758SAlexander Graf static void ppce500_power_off(void *opaque, int line, int on)
776016f7758SAlexander Graf {
777016f7758SAlexander Graf     if (on) {
778016f7758SAlexander Graf         qemu_system_shutdown_request();
779016f7758SAlexander Graf     }
780016f7758SAlexander Graf }
781016f7758SAlexander Graf 
7823ef96221SMarcel Apfelbaum void ppce500_init(MachineState *machine, PPCE500Params *params)
7831db09b84Saurel32 {
78439186d8aSRichard Henderson     MemoryRegion *address_space_mem = get_system_memory();
7852646c133SAvi Kivity     MemoryRegion *ram = g_new(MemoryRegion, 1);
7861db09b84Saurel32     PCIBus *pci_bus;
787e2684c0bSAndreas Färber     CPUPPCState *env = NULL;
7883812c71fSAlexander Graf     uint64_t loadaddr;
7893812c71fSAlexander Graf     hwaddr kernel_base = -1LL;
7903812c71fSAlexander Graf     int kernel_size = 0;
7913812c71fSAlexander Graf     hwaddr dt_base = 0;
7923812c71fSAlexander Graf     hwaddr initrd_base = 0;
7933812c71fSAlexander Graf     int initrd_size = 0;
7943812c71fSAlexander Graf     hwaddr cur_base = 0;
7953812c71fSAlexander Graf     char *filename;
7963812c71fSAlexander Graf     hwaddr bios_entry = 0;
7973812c71fSAlexander Graf     target_long bios_size;
7983812c71fSAlexander Graf     struct boot_info *boot_info;
7993812c71fSAlexander Graf     int dt_size;
80082fc73b6SScott Wood     int i;
801d575a6ceSBharat Bhushan     /* irq num for pin INTA, INTB, INTC and INTD is 1, 2, 3 and
802d575a6ceSBharat Bhushan      * 4 respectively */
803d575a6ceSBharat Bhushan     unsigned int pci_irq_nrs[PCI_NUM_PINS] = {1, 2, 3, 4};
804a915249fSAlexander Graf     qemu_irq **irqs, *mpic;
805be13cc7aSAlexander Graf     DeviceState *dev;
806e2684c0bSAndreas Färber     CPUPPCState *firstenv = NULL;
8073eddc1beSBharat Bhushan     MemoryRegion *ccsr_addr_space;
808dffb1dc2SBharat Bhushan     SysBusDevice *s;
8093eddc1beSBharat Bhushan     PPCE500CCSRState *ccsr;
8101db09b84Saurel32 
811e61c36d5SAlexander Graf     /* Setup CPUs */
8123ef96221SMarcel Apfelbaum     if (machine->cpu_model == NULL) {
8133ef96221SMarcel Apfelbaum         machine->cpu_model = "e500v2_v30";
814ef250db6SAlexander Graf     }
815ef250db6SAlexander Graf 
816a915249fSAlexander Graf     irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *));
817a915249fSAlexander Graf     irqs[0] = g_malloc0(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
818e61c36d5SAlexander Graf     for (i = 0; i < smp_cpus; i++) {
819397b457dSAndreas Färber         PowerPCCPU *cpu;
82055e5c285SAndreas Färber         CPUState *cs;
821e61c36d5SAlexander Graf         qemu_irq *input;
822397b457dSAndreas Färber 
8233ef96221SMarcel Apfelbaum         cpu = cpu_ppc_init(machine->cpu_model);
824397b457dSAndreas Färber         if (cpu == NULL) {
8251db09b84Saurel32             fprintf(stderr, "Unable to initialize CPU!\n");
8261db09b84Saurel32             exit(1);
8271db09b84Saurel32         }
828397b457dSAndreas Färber         env = &cpu->env;
82955e5c285SAndreas Färber         cs = CPU(cpu);
8301db09b84Saurel32 
831e61c36d5SAlexander Graf         if (!firstenv) {
832e61c36d5SAlexander Graf             firstenv = env;
833e61c36d5SAlexander Graf         }
834e61c36d5SAlexander Graf 
835a915249fSAlexander Graf         irqs[i] = irqs[0] + (i * OPENPIC_OUTPUT_NB);
836a915249fSAlexander Graf         input = (qemu_irq *)env->irq_inputs;
837a915249fSAlexander Graf         irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT];
838a915249fSAlexander Graf         irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT];
8396a450df9SAlexander Graf         env->spr_cb[SPR_BOOKE_PIR].default_value = cs->cpu_index = i;
8402eaaac1fSAlexander Graf         env->mpic_iack = params->ccsrbar_base +
841bd25922eSScott Wood                          MPC8544_MPIC_REGS_OFFSET + 0xa0;
842e61c36d5SAlexander Graf 
843a34a92b9SAndreas Färber         ppc_booke_timers_init(cpu, 400000000, PPC_TIMER_E500);
8443b989d49SAlexander Graf 
8453b989d49SAlexander Graf         /* Register reset handler */
8465c145dacSAlexander Graf         if (!i) {
8475c145dacSAlexander Graf             /* Primary CPU */
8485c145dacSAlexander Graf             struct boot_info *boot_info;
849e61c36d5SAlexander Graf             boot_info = g_malloc0(sizeof(struct boot_info));
850b3305981SScott Wood             qemu_register_reset(ppce500_cpu_reset, cpu);
851e61c36d5SAlexander Graf             env->load_info = boot_info;
8525c145dacSAlexander Graf         } else {
8535c145dacSAlexander Graf             /* Secondary CPUs */
854b3305981SScott Wood             qemu_register_reset(ppce500_cpu_reset_sec, cpu);
8555c145dacSAlexander Graf         }
856e61c36d5SAlexander Graf     }
857e61c36d5SAlexander Graf 
858e61c36d5SAlexander Graf     env = firstenv;
8593b989d49SAlexander Graf 
8601db09b84Saurel32     /* Fixup Memory size on a alignment boundary */
8611db09b84Saurel32     ram_size &= ~(RAM_SIZES_ALIGN - 1);
8623ef96221SMarcel Apfelbaum     machine->ram_size = ram_size;
8631db09b84Saurel32 
8641db09b84Saurel32     /* Register Memory */
865e938ba0cSShreyas B. Prabhu     memory_region_allocate_system_memory(ram, NULL, "mpc8544ds.ram", ram_size);
8662646c133SAvi Kivity     memory_region_add_subregion(address_space_mem, 0, ram);
8671db09b84Saurel32 
8683eddc1beSBharat Bhushan     dev = qdev_create(NULL, "e500-ccsr");
8693eddc1beSBharat Bhushan     object_property_add_child(qdev_get_machine(), "e500-ccsr",
8703eddc1beSBharat Bhushan                               OBJECT(dev), NULL);
8713eddc1beSBharat Bhushan     qdev_init_nofail(dev);
8723eddc1beSBharat Bhushan     ccsr = CCSR(dev);
8733eddc1beSBharat Bhushan     ccsr_addr_space = &ccsr->ccsr_space;
8742eaaac1fSAlexander Graf     memory_region_add_subregion(address_space_mem, params->ccsrbar_base,
8753eddc1beSBharat Bhushan                                 ccsr_addr_space);
876dffb1dc2SBharat Bhushan 
877446f16a6SMarcel Apfelbaum     mpic = ppce500_init_mpic(machine, params, ccsr_addr_space, irqs);
8781db09b84Saurel32 
8791db09b84Saurel32     /* Serial */
8802d48377aSBlue Swirl     if (serial_hds[0]) {
8813eddc1beSBharat Bhushan         serial_mm_init(ccsr_addr_space, MPC8544_SERIAL0_REGS_OFFSET,
882cdbb912aSAlexander Graf                        0, mpic[42], 399193,
8832ff0c7c3SRichard Henderson                        serial_hds[0], DEVICE_BIG_ENDIAN);
8842d48377aSBlue Swirl     }
8851db09b84Saurel32 
8862d48377aSBlue Swirl     if (serial_hds[1]) {
8873eddc1beSBharat Bhushan         serial_mm_init(ccsr_addr_space, MPC8544_SERIAL1_REGS_OFFSET,
888cdbb912aSAlexander Graf                        0, mpic[42], 399193,
88959de4f98SBharat Bhushan                        serial_hds[1], DEVICE_BIG_ENDIAN);
8902d48377aSBlue Swirl     }
8911db09b84Saurel32 
892b0fb8423SAlexander Graf     /* General Utility device */
893dffb1dc2SBharat Bhushan     dev = qdev_create(NULL, "mpc8544-guts");
894dffb1dc2SBharat Bhushan     qdev_init_nofail(dev);
895dffb1dc2SBharat Bhushan     s = SYS_BUS_DEVICE(dev);
8963eddc1beSBharat Bhushan     memory_region_add_subregion(ccsr_addr_space, MPC8544_UTIL_OFFSET,
897dffb1dc2SBharat Bhushan                                 sysbus_mmio_get_region(s, 0));
898b0fb8423SAlexander Graf 
8991db09b84Saurel32     /* PCI */
900dffb1dc2SBharat Bhushan     dev = qdev_create(NULL, "e500-pcihost");
901492ec48dSAlexander Graf     qdev_prop_set_uint32(dev, "first_slot", params->pci_first_slot);
9023016dca0SBharat Bhushan     qdev_prop_set_uint32(dev, "first_pin_irq", pci_irq_nrs[0]);
903dffb1dc2SBharat Bhushan     qdev_init_nofail(dev);
904dffb1dc2SBharat Bhushan     s = SYS_BUS_DEVICE(dev);
905d575a6ceSBharat Bhushan     for (i = 0; i < PCI_NUM_PINS; i++) {
906d575a6ceSBharat Bhushan         sysbus_connect_irq(s, i, mpic[pci_irq_nrs[i]]);
907d575a6ceSBharat Bhushan     }
908d575a6ceSBharat Bhushan 
9093eddc1beSBharat Bhushan     memory_region_add_subregion(ccsr_addr_space, MPC8544_PCI_REGS_OFFSET,
910dffb1dc2SBharat Bhushan                                 sysbus_mmio_get_region(s, 0));
911dffb1dc2SBharat Bhushan 
912d461e3b9SAlexander Graf     pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
9131db09b84Saurel32     if (!pci_bus)
9141db09b84Saurel32         printf("couldn't create PCI controller!\n");
9151db09b84Saurel32 
9161db09b84Saurel32     if (pci_bus) {
9171db09b84Saurel32         /* Register network interfaces. */
9181db09b84Saurel32         for (i = 0; i < nb_nics; i++) {
91929b358f9SDavid Gibson             pci_nic_init_nofail(&nd_table[i], pci_bus, "virtio", NULL);
9201db09b84Saurel32         }
9211db09b84Saurel32     }
9221db09b84Saurel32 
9235c145dacSAlexander Graf     /* Register spinning region */
9242eaaac1fSAlexander Graf     sysbus_create_simple("e500-spin", params->spin_base, NULL);
9255c145dacSAlexander Graf 
9263812c71fSAlexander Graf     if (cur_base < (32 * 1024 * 1024)) {
9273812c71fSAlexander Graf         /* u-boot occupies memory up to 32MB, so load blobs above */
9283812c71fSAlexander Graf         cur_base = (32 * 1024 * 1024);
9293812c71fSAlexander Graf     }
9303812c71fSAlexander Graf 
931b88e77f4SAlexander Graf     if (params->has_mpc8xxx_gpio) {
932016f7758SAlexander Graf         qemu_irq poweroff_irq;
933016f7758SAlexander Graf 
934b88e77f4SAlexander Graf         dev = qdev_create(NULL, "mpc8xxx_gpio");
935b88e77f4SAlexander Graf         s = SYS_BUS_DEVICE(dev);
936b88e77f4SAlexander Graf         qdev_init_nofail(dev);
937b88e77f4SAlexander Graf         sysbus_connect_irq(s, 0, mpic[MPC8XXX_GPIO_IRQ]);
938b88e77f4SAlexander Graf         memory_region_add_subregion(ccsr_addr_space, MPC8XXX_GPIO_OFFSET,
939b88e77f4SAlexander Graf                                     sysbus_mmio_get_region(s, 0));
940016f7758SAlexander Graf 
941016f7758SAlexander Graf         /* Power Off GPIO at Pin 0 */
942016f7758SAlexander Graf         poweroff_irq = qemu_allocate_irq(ppce500_power_off, NULL, 0);
943016f7758SAlexander Graf         qdev_connect_gpio_out(dev, 0, poweroff_irq);
944b88e77f4SAlexander Graf     }
945b88e77f4SAlexander Graf 
946f7087343SAlexander Graf     /* Platform Bus Device */
947f7087343SAlexander Graf     if (params->has_platform_bus) {
948f7087343SAlexander Graf         dev = qdev_create(NULL, TYPE_PLATFORM_BUS_DEVICE);
949f7087343SAlexander Graf         dev->id = TYPE_PLATFORM_BUS_DEVICE;
950f7087343SAlexander Graf         qdev_prop_set_uint32(dev, "num_irqs", params->platform_bus_num_irqs);
951f7087343SAlexander Graf         qdev_prop_set_uint32(dev, "mmio_size", params->platform_bus_size);
952f7087343SAlexander Graf         qdev_init_nofail(dev);
953f7087343SAlexander Graf         s = SYS_BUS_DEVICE(dev);
954f7087343SAlexander Graf 
955f7087343SAlexander Graf         for (i = 0; i < params->platform_bus_num_irqs; i++) {
956f7087343SAlexander Graf             int irqn = params->platform_bus_first_irq + i;
957f7087343SAlexander Graf             sysbus_connect_irq(s, i, mpic[irqn]);
958f7087343SAlexander Graf         }
959f7087343SAlexander Graf 
960f7087343SAlexander Graf         memory_region_add_subregion(address_space_mem,
961f7087343SAlexander Graf                                     params->platform_bus_base,
962f7087343SAlexander Graf                                     sysbus_mmio_get_region(s, 0));
963f7087343SAlexander Graf     }
964f7087343SAlexander Graf 
9651db09b84Saurel32     /* Load kernel. */
9663ef96221SMarcel Apfelbaum     if (machine->kernel_filename) {
9673812c71fSAlexander Graf         kernel_base = cur_base;
9683812c71fSAlexander Graf         kernel_size = load_image_targphys(machine->kernel_filename,
9693812c71fSAlexander Graf                                           cur_base,
9703812c71fSAlexander Graf                                           ram_size - cur_base);
9711db09b84Saurel32         if (kernel_size < 0) {
9721db09b84Saurel32             fprintf(stderr, "qemu: could not load kernel '%s'\n",
9733ef96221SMarcel Apfelbaum                     machine->kernel_filename);
9741db09b84Saurel32             exit(1);
9751db09b84Saurel32         }
976528e536eSAlexander Graf 
9773812c71fSAlexander Graf         cur_base += kernel_size;
9781db09b84Saurel32     }
9791db09b84Saurel32 
9801db09b84Saurel32     /* Load initrd. */
9813ef96221SMarcel Apfelbaum     if (machine->initrd_filename) {
982528e536eSAlexander Graf         initrd_base = (cur_base + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK;
9833ef96221SMarcel Apfelbaum         initrd_size = load_image_targphys(machine->initrd_filename, initrd_base,
984d7585251Spbrook                                           ram_size - initrd_base);
9851db09b84Saurel32 
9861db09b84Saurel32         if (initrd_size < 0) {
9871db09b84Saurel32             fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
9883ef96221SMarcel Apfelbaum                     machine->initrd_filename);
9891db09b84Saurel32             exit(1);
9901db09b84Saurel32         }
991528e536eSAlexander Graf 
992528e536eSAlexander Graf         cur_base = initrd_base + initrd_size;
9931db09b84Saurel32     }
9941db09b84Saurel32 
9953812c71fSAlexander Graf     /*
9963812c71fSAlexander Graf      * Smart firmware defaults ahead!
9973812c71fSAlexander Graf      *
9983812c71fSAlexander Graf      * We follow the following table to select which payload we execute.
9993812c71fSAlexander Graf      *
10003812c71fSAlexander Graf      *  -kernel | -bios | payload
10013812c71fSAlexander Graf      * ---------+-------+---------
10023812c71fSAlexander Graf      *     N    |   Y   | u-boot
10033812c71fSAlexander Graf      *     N    |   N   | u-boot
10043812c71fSAlexander Graf      *     Y    |   Y   | u-boot
10053812c71fSAlexander Graf      *     Y    |   N   | kernel
10063812c71fSAlexander Graf      *
10073812c71fSAlexander Graf      * This ensures backwards compatibility with how we used to expose
10083812c71fSAlexander Graf      * -kernel to users but allows them to run through u-boot as well.
10093812c71fSAlexander Graf      */
10103812c71fSAlexander Graf     if (bios_name == NULL) {
10113ef96221SMarcel Apfelbaum         if (machine->kernel_filename) {
10123812c71fSAlexander Graf             bios_name = machine->kernel_filename;
10133812c71fSAlexander Graf         } else {
10143812c71fSAlexander Graf             bios_name = "u-boot.e500";
10153812c71fSAlexander Graf         }
10163812c71fSAlexander Graf     }
10173812c71fSAlexander Graf     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
10183812c71fSAlexander Graf 
10193812c71fSAlexander Graf     bios_size = load_elf(filename, NULL, NULL, &bios_entry, &loadaddr, NULL,
10204ecd4d16SPeter Crosthwaite                          1, PPC_ELF_MACHINE, 0);
10213812c71fSAlexander Graf     if (bios_size < 0) {
10223812c71fSAlexander Graf         /*
10233812c71fSAlexander Graf          * Hrm. No ELF image? Try a uImage, maybe someone is giving us an
10243812c71fSAlexander Graf          * ePAPR compliant kernel
10253812c71fSAlexander Graf          */
102625bda50aSMax Filippov         kernel_size = load_uimage(filename, &bios_entry, &loadaddr, NULL,
102725bda50aSMax Filippov                                   NULL, NULL);
10283812c71fSAlexander Graf         if (kernel_size < 0) {
10293812c71fSAlexander Graf             fprintf(stderr, "qemu: could not load firmware '%s'\n", filename);
10303812c71fSAlexander Graf             exit(1);
10313812c71fSAlexander Graf         }
10323812c71fSAlexander Graf     }
1033f19377bfSShannon Zhao     g_free(filename);
10343812c71fSAlexander Graf 
10353812c71fSAlexander Graf     /* Reserve space for dtb */
10363812c71fSAlexander Graf     dt_base = (loadaddr + bios_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
10375c145dacSAlexander Graf 
10383ef96221SMarcel Apfelbaum     dt_size = ppce500_prep_device_tree(machine, params, dt_base,
1039903585deSAlexander Graf                                        initrd_base, initrd_size,
10403812c71fSAlexander Graf                                        kernel_base, kernel_size);
1041cba2026aSAlexander Graf     if (dt_size < 0) {
10421db09b84Saurel32         fprintf(stderr, "couldn't load device tree\n");
10431db09b84Saurel32         exit(1);
10441db09b84Saurel32     }
1045b8dec144SAlexander Graf     assert(dt_size < DTB_MAX_SIZE);
10461db09b84Saurel32 
1047e61c36d5SAlexander Graf     boot_info = env->load_info;
10483812c71fSAlexander Graf     boot_info->entry = bios_entry;
10493b989d49SAlexander Graf     boot_info->dt_base = dt_base;
1050cba2026aSAlexander Graf     boot_info->dt_size = dt_size;
10511db09b84Saurel32 }
10523eddc1beSBharat Bhushan 
10533eddc1beSBharat Bhushan static int e500_ccsr_initfn(SysBusDevice *dev)
10543eddc1beSBharat Bhushan {
10553eddc1beSBharat Bhushan     PPCE500CCSRState *ccsr;
10563eddc1beSBharat Bhushan 
10573eddc1beSBharat Bhushan     ccsr = CCSR(dev);
105840c5dce9SPaolo Bonzini     memory_region_init(&ccsr->ccsr_space, OBJECT(ccsr), "e500-ccsr",
10593eddc1beSBharat Bhushan                        MPC8544_CCSRBAR_SIZE);
10603eddc1beSBharat Bhushan     return 0;
10613eddc1beSBharat Bhushan }
10623eddc1beSBharat Bhushan 
10633eddc1beSBharat Bhushan static void e500_ccsr_class_init(ObjectClass *klass, void *data)
10643eddc1beSBharat Bhushan {
10653eddc1beSBharat Bhushan     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
10663eddc1beSBharat Bhushan     k->init = e500_ccsr_initfn;
10673eddc1beSBharat Bhushan }
10683eddc1beSBharat Bhushan 
10693eddc1beSBharat Bhushan static const TypeInfo e500_ccsr_info = {
10703eddc1beSBharat Bhushan     .name          = TYPE_CCSR,
10713eddc1beSBharat Bhushan     .parent        = TYPE_SYS_BUS_DEVICE,
10723eddc1beSBharat Bhushan     .instance_size = sizeof(PPCE500CCSRState),
10733eddc1beSBharat Bhushan     .class_init    = e500_ccsr_class_init,
10743eddc1beSBharat Bhushan };
10753eddc1beSBharat Bhushan 
10763eddc1beSBharat Bhushan static void e500_register_types(void)
10773eddc1beSBharat Bhushan {
10783eddc1beSBharat Bhushan     type_register_static(&e500_ccsr_info);
10793eddc1beSBharat Bhushan }
10803eddc1beSBharat Bhushan 
10813eddc1beSBharat Bhushan type_init(e500_register_types)
1082