xref: /qemu/hw/ppc/e500.c (revision 90ee4e01a1cddcb56bd65f10dd80aad7f86b5829)
11db09b84Saurel32 /*
2b3305981SScott Wood  * QEMU PowerPC e500-based platforms
31db09b84Saurel32  *
41db09b84Saurel32  * Copyright (C) 2009 Freescale Semiconductor, Inc. All rights reserved.
51db09b84Saurel32  *
61db09b84Saurel32  * Author: Yu Liu,     <yu.liu@freescale.com>
71db09b84Saurel32  *
81db09b84Saurel32  * This file is derived from hw/ppc440_bamboo.c,
91db09b84Saurel32  * the copyright for that material belongs to the original owners.
101db09b84Saurel32  *
111db09b84Saurel32  * This is free software; you can redistribute it and/or modify
121db09b84Saurel32  * it under the terms of  the GNU General  Public License as published by
131db09b84Saurel32  * the Free Software Foundation;  either version 2 of the  License, or
141db09b84Saurel32  * (at your option) any later version.
151db09b84Saurel32  */
161db09b84Saurel32 
170d75590dSPeter Maydell #include "qemu/osdep.h"
18da34e65cSMarkus Armbruster #include "qapi/error.h"
19e6eaabebSScott Wood #include "e500.h"
203eddc1beSBharat Bhushan #include "e500-ccsr.h"
211422e32dSPaolo Bonzini #include "net/net.h"
221de7afc9SPaolo Bonzini #include "qemu/config-file.h"
234a18e7c9SScott Wood #include "hw/hw.h"
240d09e41aSPaolo Bonzini #include "hw/char/serial.h"
25a2cb15b0SMichael S. Tsirkin #include "hw/pci/pci.h"
264a18e7c9SScott Wood #include "hw/boards.h"
279c17d615SPaolo Bonzini #include "sysemu/sysemu.h"
289c17d615SPaolo Bonzini #include "sysemu/kvm.h"
291db09b84Saurel32 #include "kvm_ppc.h"
309c17d615SPaolo Bonzini #include "sysemu/device_tree.h"
310d09e41aSPaolo Bonzini #include "hw/ppc/openpic.h"
328d085cf0SMark Cave-Ayland #include "hw/ppc/openpic_kvm.h"
330d09e41aSPaolo Bonzini #include "hw/ppc/ppc.h"
344a18e7c9SScott Wood #include "hw/loader.h"
35ca20cf32SBlue Swirl #include "elf.h"
364a18e7c9SScott Wood #include "hw/sysbus.h"
37022c62cbSPaolo Bonzini #include "exec/address-spaces.h"
381de7afc9SPaolo Bonzini #include "qemu/host-utils.h"
39922a01a0SMarkus Armbruster #include "qemu/option.h"
400d09e41aSPaolo Bonzini #include "hw/pci-host/ppce500.h"
41f7087343SAlexander Graf #include "qemu/error-report.h"
42f7087343SAlexander Graf #include "hw/platform-bus.h"
43fdfb7f2cSAlexander Graf #include "hw/net/fsl_etsec/etsec.h"
441db09b84Saurel32 
45cefd3cdbSBharat Bhushan #define EPAPR_MAGIC                (0x45504150)
461db09b84Saurel32 #define BINARY_DEVICE_TREE_FILE    "mpc8544ds.dtb"
479dd5eba1SScott Wood #define DTC_LOAD_PAD               0x1800000
4875bb6589SLiu Yu #define DTC_PAD_MASK               0xFFFFF
49b8dec144SAlexander Graf #define DTB_MAX_SIZE               (8 * 1024 * 1024)
5075bb6589SLiu Yu #define INITRD_LOAD_PAD            0x2000000
5175bb6589SLiu Yu #define INITRD_PAD_MASK            0xFFFFFF
521db09b84Saurel32 
531db09b84Saurel32 #define RAM_SIZES_ALIGN            (64UL << 20)
541db09b84Saurel32 
55b3305981SScott Wood /* TODO: parameterize */
56ed2bc496SAlexander Graf #define MPC8544_CCSRBAR_SIZE       0x00100000ULL
57dffb1dc2SBharat Bhushan #define MPC8544_MPIC_REGS_OFFSET   0x40000ULL
58a911b7a9SAlexander Graf #define MPC8544_MSI_REGS_OFFSET   0x41600ULL
59dffb1dc2SBharat Bhushan #define MPC8544_SERIAL0_REGS_OFFSET 0x4500ULL
60dffb1dc2SBharat Bhushan #define MPC8544_SERIAL1_REGS_OFFSET 0x4600ULL
61dffb1dc2SBharat Bhushan #define MPC8544_PCI_REGS_OFFSET    0x8000ULL
62ed2bc496SAlexander Graf #define MPC8544_PCI_REGS_SIZE      0x1000ULL
63dffb1dc2SBharat Bhushan #define MPC8544_UTIL_OFFSET        0xe0000ULL
64b88e77f4SAlexander Graf #define MPC8XXX_GPIO_OFFSET        0x000FF000ULL
6582e345f5SAmit Tomar #define MPC8XXX_GPIO_IRQ           47
661db09b84Saurel32 
673b989d49SAlexander Graf struct boot_info
683b989d49SAlexander Graf {
693b989d49SAlexander Graf     uint32_t dt_base;
70cba2026aSAlexander Graf     uint32_t dt_size;
713b989d49SAlexander Graf     uint32_t entry;
723b989d49SAlexander Graf };
733b989d49SAlexander Graf 
74347dd79dSAlexander Graf static uint32_t *pci_map_create(void *fdt, uint32_t mpic, int first_slot,
75347dd79dSAlexander Graf                                 int nr_slots, int *len)
760dbc0798SAlexander Graf {
77347dd79dSAlexander Graf     int i = 0;
78347dd79dSAlexander Graf     int slot;
79347dd79dSAlexander Graf     int pci_irq;
809e2c1298SAlexander Graf     int host_irq;
81347dd79dSAlexander Graf     int last_slot = first_slot + nr_slots;
82347dd79dSAlexander Graf     uint32_t *pci_map;
830dbc0798SAlexander Graf 
84347dd79dSAlexander Graf     *len = nr_slots * 4 * 7 * sizeof(uint32_t);
85347dd79dSAlexander Graf     pci_map = g_malloc(*len);
86347dd79dSAlexander Graf 
87347dd79dSAlexander Graf     for (slot = first_slot; slot < last_slot; slot++) {
88347dd79dSAlexander Graf         for (pci_irq = 0; pci_irq < 4; pci_irq++) {
89347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(slot << 11);
90347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(0x0);
91347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(0x0);
92347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(pci_irq + 1);
93347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(mpic);
949e2c1298SAlexander Graf             host_irq = ppce500_pci_map_irq_slot(slot, pci_irq);
959e2c1298SAlexander Graf             pci_map[i++] = cpu_to_be32(host_irq + 1);
96347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(0x1);
970dbc0798SAlexander Graf         }
980dbc0798SAlexander Graf     }
990dbc0798SAlexander Graf 
100347dd79dSAlexander Graf     assert((i * sizeof(uint32_t)) == *len);
101347dd79dSAlexander Graf 
102347dd79dSAlexander Graf     return pci_map;
103347dd79dSAlexander Graf }
104347dd79dSAlexander Graf 
105a053a7ceSAlexander Graf static void dt_serial_create(void *fdt, unsigned long long offset,
106a053a7ceSAlexander Graf                              const char *soc, const char *mpic,
107a053a7ceSAlexander Graf                              const char *alias, int idx, bool defcon)
108a053a7ceSAlexander Graf {
109a053a7ceSAlexander Graf     char ser[128];
110a053a7ceSAlexander Graf 
111a053a7ceSAlexander Graf     snprintf(ser, sizeof(ser), "%s/serial@%llx", soc, offset);
1125a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, ser);
1135a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, ser, "device_type", "serial");
1145a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, ser, "compatible", "ns16550");
1155a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, ser, "reg", offset, 0x100);
1165a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, ser, "cell-index", idx);
1175a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, ser, "clock-frequency", 0);
1185a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, ser, "interrupts", 42, 2);
1195a4348d1SPeter Crosthwaite     qemu_fdt_setprop_phandle(fdt, ser, "interrupt-parent", mpic);
1205a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, "/aliases", alias, ser);
121a053a7ceSAlexander Graf 
122a053a7ceSAlexander Graf     if (defcon) {
123*90ee4e01SNikunj A Dadhania         /*
124*90ee4e01SNikunj A Dadhania          * "linux,stdout-path" and "stdout" properties are deprecated by linux
125*90ee4e01SNikunj A Dadhania          * kernel. New platforms should only use the "stdout-path" property. Set
126*90ee4e01SNikunj A Dadhania          * the new property and continue using older property to remain
127*90ee4e01SNikunj A Dadhania          * compatible with the existing firmware.
128*90ee4e01SNikunj A Dadhania          */
1295a4348d1SPeter Crosthwaite         qemu_fdt_setprop_string(fdt, "/chosen", "linux,stdout-path", ser);
130*90ee4e01SNikunj A Dadhania         qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", ser);
131a053a7ceSAlexander Graf     }
132a053a7ceSAlexander Graf }
133a053a7ceSAlexander Graf 
134b88e77f4SAlexander Graf static void create_dt_mpc8xxx_gpio(void *fdt, const char *soc, const char *mpic)
135b88e77f4SAlexander Graf {
136b88e77f4SAlexander Graf     hwaddr mmio0 = MPC8XXX_GPIO_OFFSET;
137b88e77f4SAlexander Graf     int irq0 = MPC8XXX_GPIO_IRQ;
138b88e77f4SAlexander Graf     gchar *node = g_strdup_printf("%s/gpio@%"PRIx64, soc, mmio0);
139016f7758SAlexander Graf     gchar *poweroff = g_strdup_printf("%s/power-off", soc);
140016f7758SAlexander Graf     int gpio_ph;
141b88e77f4SAlexander Graf 
142b88e77f4SAlexander Graf     qemu_fdt_add_subnode(fdt, node);
143b88e77f4SAlexander Graf     qemu_fdt_setprop_string(fdt, node, "compatible", "fsl,qoriq-gpio");
144b88e77f4SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "reg", mmio0, 0x1000);
145b88e77f4SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "interrupts", irq0, 0x2);
146b88e77f4SAlexander Graf     qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", mpic);
147b88e77f4SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "#gpio-cells", 2);
148b88e77f4SAlexander Graf     qemu_fdt_setprop(fdt, node, "gpio-controller", NULL, 0);
149016f7758SAlexander Graf     gpio_ph = qemu_fdt_alloc_phandle(fdt);
150016f7758SAlexander Graf     qemu_fdt_setprop_cell(fdt, node, "phandle", gpio_ph);
151016f7758SAlexander Graf     qemu_fdt_setprop_cell(fdt, node, "linux,phandle", gpio_ph);
152016f7758SAlexander Graf 
153016f7758SAlexander Graf     /* Power Off Pin */
154016f7758SAlexander Graf     qemu_fdt_add_subnode(fdt, poweroff);
155016f7758SAlexander Graf     qemu_fdt_setprop_string(fdt, poweroff, "compatible", "gpio-poweroff");
156016f7758SAlexander Graf     qemu_fdt_setprop_cells(fdt, poweroff, "gpios", gpio_ph, 0, 0);
157b88e77f4SAlexander Graf 
158b88e77f4SAlexander Graf     g_free(node);
159016f7758SAlexander Graf     g_free(poweroff);
160b88e77f4SAlexander Graf }
161b88e77f4SAlexander Graf 
162f7087343SAlexander Graf typedef struct PlatformDevtreeData {
163f7087343SAlexander Graf     void *fdt;
164f7087343SAlexander Graf     const char *mpic;
165f7087343SAlexander Graf     int irq_start;
166f7087343SAlexander Graf     const char *node;
167f7087343SAlexander Graf     PlatformBusDevice *pbus;
168f7087343SAlexander Graf } PlatformDevtreeData;
169f7087343SAlexander Graf 
170fdfb7f2cSAlexander Graf static int create_devtree_etsec(SysBusDevice *sbdev, PlatformDevtreeData *data)
171fdfb7f2cSAlexander Graf {
172fdfb7f2cSAlexander Graf     eTSEC *etsec = ETSEC_COMMON(sbdev);
173fdfb7f2cSAlexander Graf     PlatformBusDevice *pbus = data->pbus;
174fdfb7f2cSAlexander Graf     hwaddr mmio0 = platform_bus_get_mmio_addr(pbus, sbdev, 0);
175fdfb7f2cSAlexander Graf     int irq0 = platform_bus_get_irqn(pbus, sbdev, 0);
176fdfb7f2cSAlexander Graf     int irq1 = platform_bus_get_irqn(pbus, sbdev, 1);
177fdfb7f2cSAlexander Graf     int irq2 = platform_bus_get_irqn(pbus, sbdev, 2);
178fdfb7f2cSAlexander Graf     gchar *node = g_strdup_printf("/platform/ethernet@%"PRIx64, mmio0);
179fdfb7f2cSAlexander Graf     gchar *group = g_strdup_printf("%s/queue-group", node);
180fdfb7f2cSAlexander Graf     void *fdt = data->fdt;
181fdfb7f2cSAlexander Graf 
182fdfb7f2cSAlexander Graf     assert((int64_t)mmio0 >= 0);
183fdfb7f2cSAlexander Graf     assert(irq0 >= 0);
184fdfb7f2cSAlexander Graf     assert(irq1 >= 0);
185fdfb7f2cSAlexander Graf     assert(irq2 >= 0);
186fdfb7f2cSAlexander Graf 
187fdfb7f2cSAlexander Graf     qemu_fdt_add_subnode(fdt, node);
188fdfb7f2cSAlexander Graf     qemu_fdt_setprop_string(fdt, node, "device_type", "network");
189fdfb7f2cSAlexander Graf     qemu_fdt_setprop_string(fdt, node, "compatible", "fsl,etsec2");
190fdfb7f2cSAlexander Graf     qemu_fdt_setprop_string(fdt, node, "model", "eTSEC");
191fdfb7f2cSAlexander Graf     qemu_fdt_setprop(fdt, node, "local-mac-address", etsec->conf.macaddr.a, 6);
192fdfb7f2cSAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "fixed-link", 0, 1, 1000, 0, 0);
193fdfb7f2cSAlexander Graf 
194fdfb7f2cSAlexander Graf     qemu_fdt_add_subnode(fdt, group);
195fdfb7f2cSAlexander Graf     qemu_fdt_setprop_cells(fdt, group, "reg", mmio0, 0x1000);
196fdfb7f2cSAlexander Graf     qemu_fdt_setprop_cells(fdt, group, "interrupts",
197fdfb7f2cSAlexander Graf         data->irq_start + irq0, 0x2,
198fdfb7f2cSAlexander Graf         data->irq_start + irq1, 0x2,
199fdfb7f2cSAlexander Graf         data->irq_start + irq2, 0x2);
200fdfb7f2cSAlexander Graf 
201fdfb7f2cSAlexander Graf     g_free(node);
202fdfb7f2cSAlexander Graf     g_free(group);
203fdfb7f2cSAlexander Graf 
204fdfb7f2cSAlexander Graf     return 0;
205fdfb7f2cSAlexander Graf }
206fdfb7f2cSAlexander Graf 
2074f01a637SDavid Gibson static void sysbus_device_create_devtree(SysBusDevice *sbdev, void *opaque)
208f7087343SAlexander Graf {
209f7087343SAlexander Graf     PlatformDevtreeData *data = opaque;
210f7087343SAlexander Graf     bool matched = false;
211f7087343SAlexander Graf 
212fdfb7f2cSAlexander Graf     if (object_dynamic_cast(OBJECT(sbdev), TYPE_ETSEC_COMMON)) {
213fdfb7f2cSAlexander Graf         create_devtree_etsec(sbdev, data);
214fdfb7f2cSAlexander Graf         matched = true;
215fdfb7f2cSAlexander Graf     }
216fdfb7f2cSAlexander Graf 
217f7087343SAlexander Graf     if (!matched) {
218f7087343SAlexander Graf         error_report("Device %s is not supported by this machine yet.",
219f7087343SAlexander Graf                      qdev_fw_name(DEVICE(sbdev)));
220f7087343SAlexander Graf         exit(1);
221f7087343SAlexander Graf     }
222f7087343SAlexander Graf }
223f7087343SAlexander Graf 
224f7087343SAlexander Graf static void platform_bus_create_devtree(PPCE500Params *params, void *fdt,
225f7087343SAlexander Graf                                         const char *mpic)
226f7087343SAlexander Graf {
227f7087343SAlexander Graf     gchar *node = g_strdup_printf("/platform@%"PRIx64, params->platform_bus_base);
228f7087343SAlexander Graf     const char platcomp[] = "qemu,platform\0simple-bus";
229f7087343SAlexander Graf     uint64_t addr = params->platform_bus_base;
230f7087343SAlexander Graf     uint64_t size = params->platform_bus_size;
231f7087343SAlexander Graf     int irq_start = params->platform_bus_first_irq;
232f7087343SAlexander Graf     PlatformBusDevice *pbus;
233f7087343SAlexander Graf     DeviceState *dev;
234f7087343SAlexander Graf 
235f7087343SAlexander Graf     /* Create a /platform node that we can put all devices into */
236f7087343SAlexander Graf 
237f7087343SAlexander Graf     qemu_fdt_add_subnode(fdt, node);
238f7087343SAlexander Graf     qemu_fdt_setprop(fdt, node, "compatible", platcomp, sizeof(platcomp));
239f7087343SAlexander Graf 
240f7087343SAlexander Graf     /* Our platform bus region is less than 32bit big, so 1 cell is enough for
241f7087343SAlexander Graf        address and size */
242f7087343SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "#size-cells", 1);
243f7087343SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "#address-cells", 1);
244f7087343SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "ranges", 0, addr >> 32, addr, size);
245f7087343SAlexander Graf 
246f7087343SAlexander Graf     qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", mpic);
247f7087343SAlexander Graf 
248f7087343SAlexander Graf     dev = qdev_find_recursive(sysbus_get_default(), TYPE_PLATFORM_BUS_DEVICE);
249f7087343SAlexander Graf     pbus = PLATFORM_BUS_DEVICE(dev);
250f7087343SAlexander Graf 
251f7087343SAlexander Graf     /* We can only create dt nodes for dynamic devices when they're ready */
252f7087343SAlexander Graf     if (pbus->done_gathering) {
253f7087343SAlexander Graf         PlatformDevtreeData data = {
254f7087343SAlexander Graf             .fdt = fdt,
255f7087343SAlexander Graf             .mpic = mpic,
256f7087343SAlexander Graf             .irq_start = irq_start,
257f7087343SAlexander Graf             .node = node,
258f7087343SAlexander Graf             .pbus = pbus,
259f7087343SAlexander Graf         };
260f7087343SAlexander Graf 
261f7087343SAlexander Graf         /* Loop through all dynamic sysbus devices and create nodes for them */
262f7087343SAlexander Graf         foreach_dynamic_sysbus_device(sysbus_device_create_devtree, &data);
263f7087343SAlexander Graf     }
264f7087343SAlexander Graf 
265f7087343SAlexander Graf     g_free(node);
266f7087343SAlexander Graf }
267f7087343SAlexander Graf 
2683ef96221SMarcel Apfelbaum static int ppce500_load_device_tree(MachineState *machine,
269e6eaabebSScott Wood                                     PPCE500Params *params,
270a8170e5eSAvi Kivity                                     hwaddr addr,
271a8170e5eSAvi Kivity                                     hwaddr initrd_base,
27228290f37SAlexander Graf                                     hwaddr initrd_size,
273903585deSAlexander Graf                                     hwaddr kernel_base,
274903585deSAlexander Graf                                     hwaddr kernel_size,
27528290f37SAlexander Graf                                     bool dry_run)
2761db09b84Saurel32 {
27728290f37SAlexander Graf     CPUPPCState *env = first_cpu->env_ptr;
278dbf916d8SAurelien Jarno     int ret = -1;
2793ef96221SMarcel Apfelbaum     uint64_t mem_reg_property[] = { 0, cpu_to_be64(machine->ram_size) };
2807ec632b4Spbrook     int fdt_size;
281dbf916d8SAurelien Jarno     void *fdt;
2825de6b46dSAlexander Graf     uint8_t hypercall[16];
283911d6e7aSAlexander Graf     uint32_t clock_freq = 400000000;
284911d6e7aSAlexander Graf     uint32_t tb_freq = 400000000;
285621d05e3SAlexander Graf     int i;
286ebb9518aSAlexander Graf     char compatible_sb[] = "fsl,mpc8544-immr\0simple-bus";
2875da96624SAlexander Graf     char soc[128];
28819ac9deaSAlexander Graf     char mpic[128];
28919ac9deaSAlexander Graf     uint32_t mpic_ph;
290a911b7a9SAlexander Graf     uint32_t msi_ph;
291f5038483SAlexander Graf     char gutil[128];
2920dbc0798SAlexander Graf     char pci[128];
293a911b7a9SAlexander Graf     char msi[128];
294347dd79dSAlexander Graf     uint32_t *pci_map = NULL;
295347dd79dSAlexander Graf     int len;
2963627757eSAlexander Graf     uint32_t pci_ranges[14] =
2973627757eSAlexander Graf         {
298cb3778a0SAlexander Graf             0x2000000, 0x0, params->pci_mmio_bus_base,
299cb3778a0SAlexander Graf             params->pci_mmio_base >> 32, params->pci_mmio_base,
3003627757eSAlexander Graf             0x0, 0x20000000,
3013627757eSAlexander Graf 
3023627757eSAlexander Graf             0x1000000, 0x0, 0x0,
3032eaaac1fSAlexander Graf             params->pci_pio_base >> 32, params->pci_pio_base,
3043627757eSAlexander Graf             0x0, 0x10000,
3053627757eSAlexander Graf         };
3062ff3de68SMarkus Armbruster     QemuOpts *machine_opts = qemu_get_machine_opts();
3072ff3de68SMarkus Armbruster     const char *dtb_file = qemu_opt_get(machine_opts, "dtb");
3082ff3de68SMarkus Armbruster     const char *toplevel_compat = qemu_opt_get(machine_opts, "dt_compatible");
309d1b93565SAlexander Graf 
310d1b93565SAlexander Graf     if (dtb_file) {
311d1b93565SAlexander Graf         char *filename;
312d1b93565SAlexander Graf         filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_file);
313d1b93565SAlexander Graf         if (!filename) {
314d1b93565SAlexander Graf             goto out;
315d1b93565SAlexander Graf         }
316d1b93565SAlexander Graf 
317d1b93565SAlexander Graf         fdt = load_device_tree(filename, &fdt_size);
3182343dd11SMichael Tokarev         g_free(filename);
319d1b93565SAlexander Graf         if (!fdt) {
320d1b93565SAlexander Graf             goto out;
321d1b93565SAlexander Graf         }
322d1b93565SAlexander Graf         goto done;
323d1b93565SAlexander Graf     }
3241db09b84Saurel32 
3252636fcb6SAlexander Graf     fdt = create_device_tree(&fdt_size);
3265cea8590SPaul Brook     if (fdt == NULL) {
3275cea8590SPaul Brook         goto out;
3285cea8590SPaul Brook     }
3291db09b84Saurel32 
3301db09b84Saurel32     /* Manipulate device tree in memory. */
3315a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 2);
3325a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 2);
33351b852b7SAlexander Graf 
3345a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, "/memory");
3355a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, "/memory", "device_type", "memory");
3365a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, "/memory", "reg", mem_reg_property,
3371db09b84Saurel32                      sizeof(mem_reg_property));
3381db09b84Saurel32 
3395a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, "/chosen");
3403b989d49SAlexander Graf     if (initrd_size) {
3415a4348d1SPeter Crosthwaite         ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start",
3421db09b84Saurel32                                     initrd_base);
3433b989d49SAlexander Graf         if (ret < 0) {
3441db09b84Saurel32             fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
3453b989d49SAlexander Graf         }
3461db09b84Saurel32 
3475a4348d1SPeter Crosthwaite         ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
3481db09b84Saurel32                                     (initrd_base + initrd_size));
3493b989d49SAlexander Graf         if (ret < 0) {
3501db09b84Saurel32             fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
3513b989d49SAlexander Graf         }
352903585deSAlexander Graf 
353903585deSAlexander Graf     }
354903585deSAlexander Graf 
355903585deSAlexander Graf     if (kernel_base != -1ULL) {
356903585deSAlexander Graf         qemu_fdt_setprop_cells(fdt, "/chosen", "qemu,boot-kernel",
357903585deSAlexander Graf                                      kernel_base >> 32, kernel_base,
358903585deSAlexander Graf                                      kernel_size >> 32, kernel_size);
3593b989d49SAlexander Graf     }
3601db09b84Saurel32 
3615a4348d1SPeter Crosthwaite     ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
3623ef96221SMarcel Apfelbaum                                       machine->kernel_cmdline);
3631db09b84Saurel32     if (ret < 0)
3641db09b84Saurel32         fprintf(stderr, "couldn't set /chosen/bootargs\n");
3651db09b84Saurel32 
3661db09b84Saurel32     if (kvm_enabled()) {
367911d6e7aSAlexander Graf         /* Read out host's frequencies */
368911d6e7aSAlexander Graf         clock_freq = kvmppc_get_clockfreq();
369911d6e7aSAlexander Graf         tb_freq = kvmppc_get_tbfreq();
3705de6b46dSAlexander Graf 
3715de6b46dSAlexander Graf         /* indicate KVM hypercall interface */
3725a4348d1SPeter Crosthwaite         qemu_fdt_add_subnode(fdt, "/hypervisor");
3735a4348d1SPeter Crosthwaite         qemu_fdt_setprop_string(fdt, "/hypervisor", "compatible",
3745de6b46dSAlexander Graf                                 "linux,kvm");
3755de6b46dSAlexander Graf         kvmppc_get_hypercall(env, hypercall, sizeof(hypercall));
3765a4348d1SPeter Crosthwaite         qemu_fdt_setprop(fdt, "/hypervisor", "hcall-instructions",
3775de6b46dSAlexander Graf                          hypercall, sizeof(hypercall));
3781a61a9aeSStuart Yoder         /* if KVM supports the idle hcall, set property indicating this */
3791a61a9aeSStuart Yoder         if (kvmppc_get_hasidle(env)) {
3805a4348d1SPeter Crosthwaite             qemu_fdt_setprop(fdt, "/hypervisor", "has-idle", NULL, 0);
3811a61a9aeSStuart Yoder         }
3821db09b84Saurel32     }
3831db09b84Saurel32 
384625e665bSAlexander Graf     /* Create CPU nodes */
3855a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, "/cpus");
3865a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 1);
3875a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0);
388625e665bSAlexander Graf 
3891e3debf0SAlexander Graf     /* We need to generate the cpu nodes in reverse order, so Linux can pick
3901e3debf0SAlexander Graf        the first node as boot node and be happy */
3911e3debf0SAlexander Graf     for (i = smp_cpus - 1; i >= 0; i--) {
392440c8152SAndreas Färber         CPUState *cpu;
393621d05e3SAlexander Graf         char cpu_name[128];
3942eaaac1fSAlexander Graf         uint64_t cpu_release_addr = params->spin_base + (i * 0x20);
39510f25a46SAlexander Graf 
396440c8152SAndreas Färber         cpu = qemu_get_cpu(i);
39755e5c285SAndreas Färber         if (cpu == NULL) {
3981e3debf0SAlexander Graf             continue;
3991e3debf0SAlexander Graf         }
400440c8152SAndreas Färber         env = cpu->env_ptr;
4011e3debf0SAlexander Graf 
4026d536570SSam Bobroff         snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x", i);
4035a4348d1SPeter Crosthwaite         qemu_fdt_add_subnode(fdt, cpu_name);
4045a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq);
4055a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq);
4065a4348d1SPeter Crosthwaite         qemu_fdt_setprop_string(fdt, cpu_name, "device_type", "cpu");
4076d536570SSam Bobroff         qemu_fdt_setprop_cell(fdt, cpu_name, "reg", i);
4085a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-line-size",
4091e3debf0SAlexander Graf                               env->dcache_line_size);
4105a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-line-size",
4111e3debf0SAlexander Graf                               env->icache_line_size);
4125a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-size", 0x8000);
4135a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-size", 0x8000);
4145a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "bus-frequency", 0);
41555e5c285SAndreas Färber         if (cpu->cpu_index) {
4165a4348d1SPeter Crosthwaite             qemu_fdt_setprop_string(fdt, cpu_name, "status", "disabled");
4175a4348d1SPeter Crosthwaite             qemu_fdt_setprop_string(fdt, cpu_name, "enable-method",
4185a4348d1SPeter Crosthwaite                                     "spin-table");
4195a4348d1SPeter Crosthwaite             qemu_fdt_setprop_u64(fdt, cpu_name, "cpu-release-addr",
4201d2e5c52SAlexander Graf                                  cpu_release_addr);
4211e3debf0SAlexander Graf         } else {
4225a4348d1SPeter Crosthwaite             qemu_fdt_setprop_string(fdt, cpu_name, "status", "okay");
4231e3debf0SAlexander Graf         }
4241db09b84Saurel32     }
4251db09b84Saurel32 
4265a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, "/aliases");
4275da96624SAlexander Graf     /* XXX These should go into their respective devices' code */
4282eaaac1fSAlexander Graf     snprintf(soc, sizeof(soc), "/soc@%"PRIx64, params->ccsrbar_base);
4295a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, soc);
4305a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, soc, "device_type", "soc");
4315a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, soc, "compatible", compatible_sb,
432ebb9518aSAlexander Graf                      sizeof(compatible_sb));
4335a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, soc, "#address-cells", 1);
4345a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, soc, "#size-cells", 1);
4355a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, soc, "ranges", 0x0,
4362eaaac1fSAlexander Graf                            params->ccsrbar_base >> 32, params->ccsrbar_base,
4375da96624SAlexander Graf                            MPC8544_CCSRBAR_SIZE);
4385da96624SAlexander Graf     /* XXX should contain a reasonable value */
4395a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, soc, "bus-frequency", 0);
4405da96624SAlexander Graf 
441dffb1dc2SBharat Bhushan     snprintf(mpic, sizeof(mpic), "%s/pic@%llx", soc, MPC8544_MPIC_REGS_OFFSET);
4425a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, mpic);
4435a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, mpic, "device_type", "open-pic");
4445a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, mpic, "compatible", "fsl,mpic");
4455a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_OFFSET,
446dffb1dc2SBharat Bhushan                            0x40000);
4475a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, mpic, "#address-cells", 0);
4485a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, mpic, "#interrupt-cells", 2);
4495a4348d1SPeter Crosthwaite     mpic_ph = qemu_fdt_alloc_phandle(fdt);
4505a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, mpic, "phandle", mpic_ph);
4515a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, mpic, "linux,phandle", mpic_ph);
4525a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, mpic, "interrupt-controller", NULL, 0);
45319ac9deaSAlexander Graf 
4540cfc6e8dSAlexander Graf     /*
4550cfc6e8dSAlexander Graf      * We have to generate ser1 first, because Linux takes the first
4560cfc6e8dSAlexander Graf      * device it finds in the dt as serial output device. And we generate
4570cfc6e8dSAlexander Graf      * devices in reverse order to the dt.
4580cfc6e8dSAlexander Graf      */
45979c0ff2cSAlexander Graf     if (serial_hds[1]) {
460dffb1dc2SBharat Bhushan         dt_serial_create(fdt, MPC8544_SERIAL1_REGS_OFFSET,
461a053a7ceSAlexander Graf                          soc, mpic, "serial1", 1, false);
46279c0ff2cSAlexander Graf     }
46379c0ff2cSAlexander Graf 
46479c0ff2cSAlexander Graf     if (serial_hds[0]) {
465dffb1dc2SBharat Bhushan         dt_serial_create(fdt, MPC8544_SERIAL0_REGS_OFFSET,
466a053a7ceSAlexander Graf                          soc, mpic, "serial0", 0, true);
46779c0ff2cSAlexander Graf     }
4680cfc6e8dSAlexander Graf 
469ed2bc496SAlexander Graf     snprintf(gutil, sizeof(gutil), "%s/global-utilities@%llx", soc,
470dffb1dc2SBharat Bhushan              MPC8544_UTIL_OFFSET);
4715a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, gutil);
4725a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, gutil, "compatible", "fsl,mpc8544-guts");
4735a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, gutil, "reg", MPC8544_UTIL_OFFSET, 0x1000);
4745a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, gutil, "fsl,has-rstcr", NULL, 0);
475f5038483SAlexander Graf 
476a911b7a9SAlexander Graf     snprintf(msi, sizeof(msi), "/%s/msi@%llx", soc, MPC8544_MSI_REGS_OFFSET);
4775a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, msi);
4785a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, msi, "compatible", "fsl,mpic-msi");
4795a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, msi, "reg", MPC8544_MSI_REGS_OFFSET, 0x200);
4805a4348d1SPeter Crosthwaite     msi_ph = qemu_fdt_alloc_phandle(fdt);
4815a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, msi, "msi-available-ranges", 0x0, 0x100);
4825a4348d1SPeter Crosthwaite     qemu_fdt_setprop_phandle(fdt, msi, "interrupt-parent", mpic);
4835a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, msi, "interrupts",
484a911b7a9SAlexander Graf         0xe0, 0x0,
485a911b7a9SAlexander Graf         0xe1, 0x0,
486a911b7a9SAlexander Graf         0xe2, 0x0,
487a911b7a9SAlexander Graf         0xe3, 0x0,
488a911b7a9SAlexander Graf         0xe4, 0x0,
489a911b7a9SAlexander Graf         0xe5, 0x0,
490a911b7a9SAlexander Graf         0xe6, 0x0,
491a911b7a9SAlexander Graf         0xe7, 0x0);
4925a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, msi, "phandle", msi_ph);
4935a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, msi, "linux,phandle", msi_ph);
494a911b7a9SAlexander Graf 
4952eaaac1fSAlexander Graf     snprintf(pci, sizeof(pci), "/pci@%llx",
4962eaaac1fSAlexander Graf              params->ccsrbar_base + MPC8544_PCI_REGS_OFFSET);
4975a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, pci);
4985a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "cell-index", 0);
4995a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, pci, "compatible", "fsl,mpc8540-pci");
5005a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, pci, "device_type", "pci");
5015a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, pci, "interrupt-map-mask", 0xf800, 0x0,
5020dbc0798SAlexander Graf                            0x0, 0x7);
5035a4348d1SPeter Crosthwaite     pci_map = pci_map_create(fdt, qemu_fdt_get_phandle(fdt, mpic),
504492ec48dSAlexander Graf                              params->pci_first_slot, params->pci_nr_slots,
505492ec48dSAlexander Graf                              &len);
5065a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, pci, "interrupt-map", pci_map, len);
5075a4348d1SPeter Crosthwaite     qemu_fdt_setprop_phandle(fdt, pci, "interrupt-parent", mpic);
5085a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, pci, "interrupts", 24, 2);
5095a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, pci, "bus-range", 0, 255);
5103627757eSAlexander Graf     for (i = 0; i < 14; i++) {
5110dbc0798SAlexander Graf         pci_ranges[i] = cpu_to_be32(pci_ranges[i]);
5120dbc0798SAlexander Graf     }
5135a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "fsl,msi", msi_ph);
5145a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, pci, "ranges", pci_ranges, sizeof(pci_ranges));
5152eaaac1fSAlexander Graf     qemu_fdt_setprop_cells(fdt, pci, "reg",
5162eaaac1fSAlexander Graf                            (params->ccsrbar_base + MPC8544_PCI_REGS_OFFSET) >> 32,
5172eaaac1fSAlexander Graf                            (params->ccsrbar_base + MPC8544_PCI_REGS_OFFSET),
5182eaaac1fSAlexander Graf                            0, 0x1000);
5195a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "clock-frequency", 66666666);
5205a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "#interrupt-cells", 1);
5215a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "#size-cells", 2);
5225a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "#address-cells", 3);
5235a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, "/aliases", "pci0", pci);
5240dbc0798SAlexander Graf 
525b88e77f4SAlexander Graf     if (params->has_mpc8xxx_gpio) {
526b88e77f4SAlexander Graf         create_dt_mpc8xxx_gpio(fdt, soc, mpic);
527b88e77f4SAlexander Graf     }
528b88e77f4SAlexander Graf 
529f7087343SAlexander Graf     if (params->has_platform_bus) {
530f7087343SAlexander Graf         platform_bus_create_devtree(params, fdt, mpic);
531f7087343SAlexander Graf     }
532f7087343SAlexander Graf 
533e6eaabebSScott Wood     params->fixup_devtree(params, fdt);
534e6eaabebSScott Wood 
535e6eaabebSScott Wood     if (toplevel_compat) {
5365a4348d1SPeter Crosthwaite         qemu_fdt_setprop(fdt, "/", "compatible", toplevel_compat,
537e6eaabebSScott Wood                          strlen(toplevel_compat) + 1);
538e6eaabebSScott Wood     }
539e6eaabebSScott Wood 
540d1b93565SAlexander Graf done:
54128290f37SAlexander Graf     if (!dry_run) {
5425a4348d1SPeter Crosthwaite         qemu_fdt_dumpdtb(fdt, fdt_size);
54328290f37SAlexander Graf         cpu_physical_memory_write(addr, fdt, fdt_size);
544cba2026aSAlexander Graf     }
545cba2026aSAlexander Graf     ret = fdt_size;
5467ec632b4Spbrook 
5471db09b84Saurel32 out:
548347dd79dSAlexander Graf     g_free(pci_map);
5491db09b84Saurel32 
55004088adbSLiu Yu     return ret;
5511db09b84Saurel32 }
5521db09b84Saurel32 
55328290f37SAlexander Graf typedef struct DeviceTreeParams {
5543ef96221SMarcel Apfelbaum     MachineState *machine;
55528290f37SAlexander Graf     PPCE500Params params;
55628290f37SAlexander Graf     hwaddr addr;
55728290f37SAlexander Graf     hwaddr initrd_base;
55828290f37SAlexander Graf     hwaddr initrd_size;
559903585deSAlexander Graf     hwaddr kernel_base;
560903585deSAlexander Graf     hwaddr kernel_size;
561f7087343SAlexander Graf     Notifier notifier;
56228290f37SAlexander Graf } DeviceTreeParams;
56328290f37SAlexander Graf 
56428290f37SAlexander Graf static void ppce500_reset_device_tree(void *opaque)
56528290f37SAlexander Graf {
56628290f37SAlexander Graf     DeviceTreeParams *p = opaque;
5673812c71fSAlexander Graf     ppce500_load_device_tree(p->machine, &p->params, p->addr, p->initrd_base,
568903585deSAlexander Graf                              p->initrd_size, p->kernel_base, p->kernel_size,
569903585deSAlexander Graf                              false);
57028290f37SAlexander Graf }
57128290f37SAlexander Graf 
572f7087343SAlexander Graf static void ppce500_init_notify(Notifier *notifier, void *data)
573f7087343SAlexander Graf {
574f7087343SAlexander Graf     DeviceTreeParams *p = container_of(notifier, DeviceTreeParams, notifier);
575f7087343SAlexander Graf     ppce500_reset_device_tree(p);
576f7087343SAlexander Graf }
577f7087343SAlexander Graf 
5783ef96221SMarcel Apfelbaum static int ppce500_prep_device_tree(MachineState *machine,
57928290f37SAlexander Graf                                     PPCE500Params *params,
58028290f37SAlexander Graf                                     hwaddr addr,
58128290f37SAlexander Graf                                     hwaddr initrd_base,
582903585deSAlexander Graf                                     hwaddr initrd_size,
583903585deSAlexander Graf                                     hwaddr kernel_base,
584903585deSAlexander Graf                                     hwaddr kernel_size)
58528290f37SAlexander Graf {
58628290f37SAlexander Graf     DeviceTreeParams *p = g_new(DeviceTreeParams, 1);
5873ef96221SMarcel Apfelbaum     p->machine = machine;
58828290f37SAlexander Graf     p->params = *params;
58928290f37SAlexander Graf     p->addr = addr;
59028290f37SAlexander Graf     p->initrd_base = initrd_base;
59128290f37SAlexander Graf     p->initrd_size = initrd_size;
592903585deSAlexander Graf     p->kernel_base = kernel_base;
593903585deSAlexander Graf     p->kernel_size = kernel_size;
59428290f37SAlexander Graf 
59528290f37SAlexander Graf     qemu_register_reset(ppce500_reset_device_tree, p);
596f7087343SAlexander Graf     p->notifier.notify = ppce500_init_notify;
597f7087343SAlexander Graf     qemu_add_machine_init_done_notifier(&p->notifier);
59828290f37SAlexander Graf 
59928290f37SAlexander Graf     /* Issue the device tree loader once, so that we get the size of the blob */
6003ef96221SMarcel Apfelbaum     return ppce500_load_device_tree(machine, params, addr, initrd_base,
601903585deSAlexander Graf                                     initrd_size, kernel_base, kernel_size,
602903585deSAlexander Graf                                     true);
60328290f37SAlexander Graf }
60428290f37SAlexander Graf 
605cba2026aSAlexander Graf /* Create -kernel TLB entries for BookE.  */
606a36848ffSAaron Larson hwaddr booke206_page_size_to_tlb(uint64_t size)
607d1e256feSAlexander Graf {
608cba2026aSAlexander Graf     return 63 - clz64(size >> 10);
609d1e256feSAlexander Graf }
610d1e256feSAlexander Graf 
611cefd3cdbSBharat Bhushan static int booke206_initial_map_tsize(CPUPPCState *env)
6123b989d49SAlexander Graf {
613cba2026aSAlexander Graf     struct boot_info *bi = env->load_info;
614cefd3cdbSBharat Bhushan     hwaddr dt_end;
615cba2026aSAlexander Graf     int ps;
6163b989d49SAlexander Graf 
617cba2026aSAlexander Graf     /* Our initial TLB entry needs to cover everything from 0 to
618cba2026aSAlexander Graf        the device tree top */
619cba2026aSAlexander Graf     dt_end = bi->dt_base + bi->dt_size;
620cba2026aSAlexander Graf     ps = booke206_page_size_to_tlb(dt_end) + 1;
621fb37c302SAlexander Graf     if (ps & 1) {
622fb37c302SAlexander Graf         /* e500v2 can only do even TLB size bits */
623fb37c302SAlexander Graf         ps++;
624fb37c302SAlexander Graf     }
625cefd3cdbSBharat Bhushan     return ps;
626cefd3cdbSBharat Bhushan }
627cefd3cdbSBharat Bhushan 
628cefd3cdbSBharat Bhushan static uint64_t mmubooke_initial_mapsize(CPUPPCState *env)
629cefd3cdbSBharat Bhushan {
630cefd3cdbSBharat Bhushan     int tsize;
631cefd3cdbSBharat Bhushan 
632cefd3cdbSBharat Bhushan     tsize = booke206_initial_map_tsize(env);
633cefd3cdbSBharat Bhushan     return (1ULL << 10 << tsize);
634cefd3cdbSBharat Bhushan }
635cefd3cdbSBharat Bhushan 
636cefd3cdbSBharat Bhushan static void mmubooke_create_initial_mapping(CPUPPCState *env)
637cefd3cdbSBharat Bhushan {
638cefd3cdbSBharat Bhushan     ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0);
639cefd3cdbSBharat Bhushan     hwaddr size;
640cefd3cdbSBharat Bhushan     int ps;
641cefd3cdbSBharat Bhushan 
642cefd3cdbSBharat Bhushan     ps = booke206_initial_map_tsize(env);
643cba2026aSAlexander Graf     size = (ps << MAS1_TSIZE_SHIFT);
644d1e256feSAlexander Graf     tlb->mas1 = MAS1_VALID | size;
645cba2026aSAlexander Graf     tlb->mas2 = 0;
646cba2026aSAlexander Graf     tlb->mas7_3 = 0;
647d1e256feSAlexander Graf     tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
64893dd5e85SScott Wood 
64993dd5e85SScott Wood     env->tlb_dirty = true;
6503b989d49SAlexander Graf }
6513b989d49SAlexander Graf 
652b3305981SScott Wood static void ppce500_cpu_reset_sec(void *opaque)
6535c145dacSAlexander Graf {
65438f92da6SAndreas Färber     PowerPCCPU *cpu = opaque;
655259186a7SAndreas Färber     CPUState *cs = CPU(cpu);
6565c145dacSAlexander Graf 
657259186a7SAndreas Färber     cpu_reset(cs);
6585c145dacSAlexander Graf 
6595c145dacSAlexander Graf     /* Secondary CPU starts in halted state for now. Needs to change when
6605c145dacSAlexander Graf        implementing non-kernel boot. */
661259186a7SAndreas Färber     cs->halted = 1;
66227103424SAndreas Färber     cs->exception_index = EXCP_HLT;
6633b989d49SAlexander Graf }
6643b989d49SAlexander Graf 
665b3305981SScott Wood static void ppce500_cpu_reset(void *opaque)
6663b989d49SAlexander Graf {
66738f92da6SAndreas Färber     PowerPCCPU *cpu = opaque;
668259186a7SAndreas Färber     CPUState *cs = CPU(cpu);
66938f92da6SAndreas Färber     CPUPPCState *env = &cpu->env;
6703b989d49SAlexander Graf     struct boot_info *bi = env->load_info;
6713b989d49SAlexander Graf 
672259186a7SAndreas Färber     cpu_reset(cs);
6733b989d49SAlexander Graf 
6743b989d49SAlexander Graf     /* Set initial guest state. */
675259186a7SAndreas Färber     cs->halted = 0;
6763b989d49SAlexander Graf     env->gpr[1] = (16<<20) - 8;
6773b989d49SAlexander Graf     env->gpr[3] = bi->dt_base;
678cefd3cdbSBharat Bhushan     env->gpr[4] = 0;
679cefd3cdbSBharat Bhushan     env->gpr[5] = 0;
680cefd3cdbSBharat Bhushan     env->gpr[6] = EPAPR_MAGIC;
681cefd3cdbSBharat Bhushan     env->gpr[7] = mmubooke_initial_mapsize(env);
682cefd3cdbSBharat Bhushan     env->gpr[8] = 0;
683cefd3cdbSBharat Bhushan     env->gpr[9] = 0;
6843b989d49SAlexander Graf     env->nip = bi->entry;
685cba2026aSAlexander Graf     mmubooke_create_initial_mapping(env);
6863b989d49SAlexander Graf }
6873b989d49SAlexander Graf 
688d85937e6SScott Wood static DeviceState *ppce500_init_mpic_qemu(PPCE500Params *params,
68982fc73b6SScott Wood                                            qemu_irq **irqs)
69082fc73b6SScott Wood {
69182fc73b6SScott Wood     DeviceState *dev;
69282fc73b6SScott Wood     SysBusDevice *s;
69382fc73b6SScott Wood     int i, j, k;
69482fc73b6SScott Wood 
695e1766344SAndreas Färber     dev = qdev_create(NULL, TYPE_OPENPIC);
696e75ce32aSMichael Davidsaver     object_property_add_child(qdev_get_machine(), "pic", OBJECT(dev),
697e75ce32aSMichael Davidsaver                               &error_fatal);
69882fc73b6SScott Wood     qdev_prop_set_uint32(dev, "model", params->mpic_version);
699d85937e6SScott Wood     qdev_prop_set_uint32(dev, "nb_cpus", smp_cpus);
700d85937e6SScott Wood 
70182fc73b6SScott Wood     qdev_init_nofail(dev);
70282fc73b6SScott Wood     s = SYS_BUS_DEVICE(dev);
70382fc73b6SScott Wood 
70482fc73b6SScott Wood     k = 0;
70582fc73b6SScott Wood     for (i = 0; i < smp_cpus; i++) {
70682fc73b6SScott Wood         for (j = 0; j < OPENPIC_OUTPUT_NB; j++) {
70782fc73b6SScott Wood             sysbus_connect_irq(s, k++, irqs[i][j]);
70882fc73b6SScott Wood         }
70982fc73b6SScott Wood     }
71082fc73b6SScott Wood 
711d85937e6SScott Wood     return dev;
712d85937e6SScott Wood }
713d85937e6SScott Wood 
714d85937e6SScott Wood static DeviceState *ppce500_init_mpic_kvm(PPCE500Params *params,
715fe656ebdSMarkus Armbruster                                           qemu_irq **irqs, Error **errp)
716d85937e6SScott Wood {
717fe656ebdSMarkus Armbruster     Error *err = NULL;
718d85937e6SScott Wood     DeviceState *dev;
719d85937e6SScott Wood     CPUState *cs;
720d85937e6SScott Wood 
721dd49c038SAndreas Färber     dev = qdev_create(NULL, TYPE_KVM_OPENPIC);
722d85937e6SScott Wood     qdev_prop_set_uint32(dev, "model", params->mpic_version);
723d85937e6SScott Wood 
724fe656ebdSMarkus Armbruster     object_property_set_bool(OBJECT(dev), true, "realized", &err);
725fe656ebdSMarkus Armbruster     if (err) {
726fe656ebdSMarkus Armbruster         error_propagate(errp, err);
727fe656ebdSMarkus Armbruster         object_unparent(OBJECT(dev));
728d85937e6SScott Wood         return NULL;
729d85937e6SScott Wood     }
730d85937e6SScott Wood 
731bdc44640SAndreas Färber     CPU_FOREACH(cs) {
732d85937e6SScott Wood         if (kvm_openpic_connect_vcpu(dev, cs)) {
733d85937e6SScott Wood             fprintf(stderr, "%s: failed to connect vcpu to irqchip\n",
734d85937e6SScott Wood                     __func__);
735d85937e6SScott Wood             abort();
736d85937e6SScott Wood         }
737d85937e6SScott Wood     }
738d85937e6SScott Wood 
739d85937e6SScott Wood     return dev;
740d85937e6SScott Wood }
741d85937e6SScott Wood 
742c91c187fSMichael Davidsaver static DeviceState *ppce500_init_mpic(MachineState *machine,
743c91c187fSMichael Davidsaver                                       PPCE500Params *params,
744c91c187fSMichael Davidsaver                                       MemoryRegion *ccsr,
745c91c187fSMichael Davidsaver                                       qemu_irq **irqs)
746d85937e6SScott Wood {
747d85937e6SScott Wood     DeviceState *dev = NULL;
748d85937e6SScott Wood     SysBusDevice *s;
749d85937e6SScott Wood 
750d85937e6SScott Wood     if (kvm_enabled()) {
751fe656ebdSMarkus Armbruster         Error *err = NULL;
752d85937e6SScott Wood 
753446f16a6SMarcel Apfelbaum         if (machine_kernel_irqchip_allowed(machine)) {
754fe656ebdSMarkus Armbruster             dev = ppce500_init_mpic_kvm(params, irqs, &err);
755d85937e6SScott Wood         }
756446f16a6SMarcel Apfelbaum         if (machine_kernel_irqchip_required(machine) && !dev) {
757c29b77f9SMarkus Armbruster             error_reportf_err(err,
758c29b77f9SMarkus Armbruster                               "kernel_irqchip requested but unavailable: ");
759fe656ebdSMarkus Armbruster             exit(1);
760d85937e6SScott Wood         }
761d85937e6SScott Wood     }
762d85937e6SScott Wood 
763d85937e6SScott Wood     if (!dev) {
764d85937e6SScott Wood         dev = ppce500_init_mpic_qemu(params, irqs);
765d85937e6SScott Wood     }
766d85937e6SScott 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 
771c91c187fSMichael Davidsaver     return dev;
77282fc73b6SScott Wood }
77382fc73b6SScott Wood 
774016f7758SAlexander Graf static void ppce500_power_off(void *opaque, int line, int on)
775016f7758SAlexander Graf {
776016f7758SAlexander Graf     if (on) {
777cf83f140SEric 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};
803c91c187fSMichael Davidsaver     qemu_irq **irqs;
804c91c187fSMichael Davidsaver     DeviceState *dev, *mpicdev;
805e2684c0bSAndreas Färber     CPUPPCState *firstenv = NULL;
8063eddc1beSBharat Bhushan     MemoryRegion *ccsr_addr_space;
807dffb1dc2SBharat Bhushan     SysBusDevice *s;
8083eddc1beSBharat Bhushan     PPCE500CCSRState *ccsr;
8091db09b84Saurel32 
810a915249fSAlexander Graf     irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *));
811a915249fSAlexander Graf     irqs[0] = g_malloc0(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
812e61c36d5SAlexander Graf     for (i = 0; i < smp_cpus; i++) {
813397b457dSAndreas Färber         PowerPCCPU *cpu;
81455e5c285SAndreas Färber         CPUState *cs;
815e61c36d5SAlexander Graf         qemu_irq *input;
816397b457dSAndreas Färber 
81759e816fdSIgor Mammedov         cpu = POWERPC_CPU(cpu_create(machine->cpu_type));
818397b457dSAndreas Färber         env = &cpu->env;
81955e5c285SAndreas Färber         cs = CPU(cpu);
8201db09b84Saurel32 
82100469dc3SValentin Plotkin         if (env->mmu_model != POWERPC_MMU_BOOKE206) {
8226f76b817SAlistair Francis             error_report("MMU model %i not supported by this machine",
82300469dc3SValentin Plotkin                          env->mmu_model);
82400469dc3SValentin Plotkin             exit(1);
82500469dc3SValentin Plotkin         }
82600469dc3SValentin Plotkin 
827e61c36d5SAlexander Graf         if (!firstenv) {
828e61c36d5SAlexander Graf             firstenv = env;
829e61c36d5SAlexander Graf         }
830e61c36d5SAlexander Graf 
831a915249fSAlexander Graf         irqs[i] = irqs[0] + (i * OPENPIC_OUTPUT_NB);
832a915249fSAlexander Graf         input = (qemu_irq *)env->irq_inputs;
833a915249fSAlexander Graf         irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT];
834a915249fSAlexander Graf         irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT];
8356a450df9SAlexander Graf         env->spr_cb[SPR_BOOKE_PIR].default_value = cs->cpu_index = i;
8362eaaac1fSAlexander Graf         env->mpic_iack = params->ccsrbar_base +
837bd25922eSScott Wood                          MPC8544_MPIC_REGS_OFFSET + 0xa0;
838e61c36d5SAlexander Graf 
839a34a92b9SAndreas Färber         ppc_booke_timers_init(cpu, 400000000, PPC_TIMER_E500);
8403b989d49SAlexander Graf 
8413b989d49SAlexander Graf         /* Register reset handler */
8425c145dacSAlexander Graf         if (!i) {
8435c145dacSAlexander Graf             /* Primary CPU */
8445c145dacSAlexander Graf             struct boot_info *boot_info;
845e61c36d5SAlexander Graf             boot_info = g_malloc0(sizeof(struct boot_info));
846b3305981SScott Wood             qemu_register_reset(ppce500_cpu_reset, cpu);
847e61c36d5SAlexander Graf             env->load_info = boot_info;
8485c145dacSAlexander Graf         } else {
8495c145dacSAlexander Graf             /* Secondary CPUs */
850b3305981SScott Wood             qemu_register_reset(ppce500_cpu_reset_sec, cpu);
8515c145dacSAlexander Graf         }
852e61c36d5SAlexander Graf     }
853e61c36d5SAlexander Graf 
854e61c36d5SAlexander Graf     env = firstenv;
8553b989d49SAlexander Graf 
8561db09b84Saurel32     /* Fixup Memory size on a alignment boundary */
8571db09b84Saurel32     ram_size &= ~(RAM_SIZES_ALIGN - 1);
8583ef96221SMarcel Apfelbaum     machine->ram_size = ram_size;
8591db09b84Saurel32 
8601db09b84Saurel32     /* Register Memory */
861e938ba0cSShreyas B. Prabhu     memory_region_allocate_system_memory(ram, NULL, "mpc8544ds.ram", ram_size);
8622646c133SAvi Kivity     memory_region_add_subregion(address_space_mem, 0, ram);
8631db09b84Saurel32 
8643eddc1beSBharat Bhushan     dev = qdev_create(NULL, "e500-ccsr");
8653eddc1beSBharat Bhushan     object_property_add_child(qdev_get_machine(), "e500-ccsr",
8663eddc1beSBharat Bhushan                               OBJECT(dev), NULL);
8673eddc1beSBharat Bhushan     qdev_init_nofail(dev);
8683eddc1beSBharat Bhushan     ccsr = CCSR(dev);
8693eddc1beSBharat Bhushan     ccsr_addr_space = &ccsr->ccsr_space;
8702eaaac1fSAlexander Graf     memory_region_add_subregion(address_space_mem, params->ccsrbar_base,
8713eddc1beSBharat Bhushan                                 ccsr_addr_space);
872dffb1dc2SBharat Bhushan 
873c91c187fSMichael Davidsaver     mpicdev = ppce500_init_mpic(machine, params, ccsr_addr_space, irqs);
8741db09b84Saurel32 
8751db09b84Saurel32     /* Serial */
8762d48377aSBlue Swirl     if (serial_hds[0]) {
8773eddc1beSBharat Bhushan         serial_mm_init(ccsr_addr_space, MPC8544_SERIAL0_REGS_OFFSET,
878c91c187fSMichael Davidsaver                        0, qdev_get_gpio_in(mpicdev, 42), 399193,
8792ff0c7c3SRichard Henderson                        serial_hds[0], DEVICE_BIG_ENDIAN);
8802d48377aSBlue Swirl     }
8811db09b84Saurel32 
8822d48377aSBlue Swirl     if (serial_hds[1]) {
8833eddc1beSBharat Bhushan         serial_mm_init(ccsr_addr_space, MPC8544_SERIAL1_REGS_OFFSET,
884c91c187fSMichael Davidsaver                        0, qdev_get_gpio_in(mpicdev, 42), 399193,
88559de4f98SBharat Bhushan                        serial_hds[1], DEVICE_BIG_ENDIAN);
8862d48377aSBlue Swirl     }
8871db09b84Saurel32 
888b0fb8423SAlexander Graf     /* General Utility device */
889dffb1dc2SBharat Bhushan     dev = qdev_create(NULL, "mpc8544-guts");
890dffb1dc2SBharat Bhushan     qdev_init_nofail(dev);
891dffb1dc2SBharat Bhushan     s = SYS_BUS_DEVICE(dev);
8923eddc1beSBharat Bhushan     memory_region_add_subregion(ccsr_addr_space, MPC8544_UTIL_OFFSET,
893dffb1dc2SBharat Bhushan                                 sysbus_mmio_get_region(s, 0));
894b0fb8423SAlexander Graf 
8951db09b84Saurel32     /* PCI */
896dffb1dc2SBharat Bhushan     dev = qdev_create(NULL, "e500-pcihost");
897e75ce32aSMichael Davidsaver     object_property_add_child(qdev_get_machine(), "pci-host", OBJECT(dev),
898e75ce32aSMichael Davidsaver                               &error_abort);
899492ec48dSAlexander Graf     qdev_prop_set_uint32(dev, "first_slot", params->pci_first_slot);
9003016dca0SBharat Bhushan     qdev_prop_set_uint32(dev, "first_pin_irq", pci_irq_nrs[0]);
901dffb1dc2SBharat Bhushan     qdev_init_nofail(dev);
902dffb1dc2SBharat Bhushan     s = SYS_BUS_DEVICE(dev);
903d575a6ceSBharat Bhushan     for (i = 0; i < PCI_NUM_PINS; i++) {
904c91c187fSMichael Davidsaver         sysbus_connect_irq(s, i, qdev_get_gpio_in(mpicdev, pci_irq_nrs[i]));
905d575a6ceSBharat Bhushan     }
906d575a6ceSBharat Bhushan 
9073eddc1beSBharat Bhushan     memory_region_add_subregion(ccsr_addr_space, MPC8544_PCI_REGS_OFFSET,
908dffb1dc2SBharat Bhushan                                 sysbus_mmio_get_region(s, 0));
909dffb1dc2SBharat Bhushan 
910d461e3b9SAlexander Graf     pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
9111db09b84Saurel32     if (!pci_bus)
9121db09b84Saurel32         printf("couldn't create PCI controller!\n");
9131db09b84Saurel32 
9141db09b84Saurel32     if (pci_bus) {
9151db09b84Saurel32         /* Register network interfaces. */
9161db09b84Saurel32         for (i = 0; i < nb_nics; i++) {
91729b358f9SDavid Gibson             pci_nic_init_nofail(&nd_table[i], pci_bus, "virtio", NULL);
9181db09b84Saurel32         }
9191db09b84Saurel32     }
9201db09b84Saurel32 
9215c145dacSAlexander Graf     /* Register spinning region */
9222eaaac1fSAlexander Graf     sysbus_create_simple("e500-spin", params->spin_base, NULL);
9235c145dacSAlexander Graf 
9243812c71fSAlexander Graf     if (cur_base < (32 * 1024 * 1024)) {
9253812c71fSAlexander Graf         /* u-boot occupies memory up to 32MB, so load blobs above */
9263812c71fSAlexander Graf         cur_base = (32 * 1024 * 1024);
9273812c71fSAlexander Graf     }
9283812c71fSAlexander Graf 
929b88e77f4SAlexander Graf     if (params->has_mpc8xxx_gpio) {
930016f7758SAlexander Graf         qemu_irq poweroff_irq;
931016f7758SAlexander Graf 
932b88e77f4SAlexander Graf         dev = qdev_create(NULL, "mpc8xxx_gpio");
933b88e77f4SAlexander Graf         s = SYS_BUS_DEVICE(dev);
934b88e77f4SAlexander Graf         qdev_init_nofail(dev);
935c91c187fSMichael Davidsaver         sysbus_connect_irq(s, 0, qdev_get_gpio_in(mpicdev, MPC8XXX_GPIO_IRQ));
936b88e77f4SAlexander Graf         memory_region_add_subregion(ccsr_addr_space, MPC8XXX_GPIO_OFFSET,
937b88e77f4SAlexander Graf                                     sysbus_mmio_get_region(s, 0));
938016f7758SAlexander Graf 
939016f7758SAlexander Graf         /* Power Off GPIO at Pin 0 */
940016f7758SAlexander Graf         poweroff_irq = qemu_allocate_irq(ppce500_power_off, NULL, 0);
941016f7758SAlexander Graf         qdev_connect_gpio_out(dev, 0, poweroff_irq);
942b88e77f4SAlexander Graf     }
943b88e77f4SAlexander Graf 
944f7087343SAlexander Graf     /* Platform Bus Device */
945f7087343SAlexander Graf     if (params->has_platform_bus) {
946f7087343SAlexander Graf         dev = qdev_create(NULL, TYPE_PLATFORM_BUS_DEVICE);
947f7087343SAlexander Graf         dev->id = TYPE_PLATFORM_BUS_DEVICE;
948f7087343SAlexander Graf         qdev_prop_set_uint32(dev, "num_irqs", params->platform_bus_num_irqs);
949f7087343SAlexander Graf         qdev_prop_set_uint32(dev, "mmio_size", params->platform_bus_size);
950f7087343SAlexander Graf         qdev_init_nofail(dev);
951f7087343SAlexander Graf         s = SYS_BUS_DEVICE(dev);
952f7087343SAlexander Graf 
953f7087343SAlexander Graf         for (i = 0; i < params->platform_bus_num_irqs; i++) {
954f7087343SAlexander Graf             int irqn = params->platform_bus_first_irq + i;
955c91c187fSMichael Davidsaver             sysbus_connect_irq(s, i, qdev_get_gpio_in(mpicdev, irqn));
956f7087343SAlexander Graf         }
957f7087343SAlexander Graf 
958f7087343SAlexander Graf         memory_region_add_subregion(address_space_mem,
959f7087343SAlexander Graf                                     params->platform_bus_base,
960f7087343SAlexander Graf                                     sysbus_mmio_get_region(s, 0));
961f7087343SAlexander Graf     }
962f7087343SAlexander Graf 
9631db09b84Saurel32     /* Load kernel. */
9643ef96221SMarcel Apfelbaum     if (machine->kernel_filename) {
9653812c71fSAlexander Graf         kernel_base = cur_base;
9663812c71fSAlexander Graf         kernel_size = load_image_targphys(machine->kernel_filename,
9673812c71fSAlexander Graf                                           cur_base,
9683812c71fSAlexander Graf                                           ram_size - cur_base);
9691db09b84Saurel32         if (kernel_size < 0) {
9706f76b817SAlistair Francis             error_report("could not load kernel '%s'",
9713ef96221SMarcel Apfelbaum                          machine->kernel_filename);
9721db09b84Saurel32             exit(1);
9731db09b84Saurel32         }
974528e536eSAlexander Graf 
9753812c71fSAlexander Graf         cur_base += kernel_size;
9761db09b84Saurel32     }
9771db09b84Saurel32 
9781db09b84Saurel32     /* Load initrd. */
9793ef96221SMarcel Apfelbaum     if (machine->initrd_filename) {
980528e536eSAlexander Graf         initrd_base = (cur_base + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK;
9813ef96221SMarcel Apfelbaum         initrd_size = load_image_targphys(machine->initrd_filename, initrd_base,
982d7585251Spbrook                                           ram_size - initrd_base);
9831db09b84Saurel32 
9841db09b84Saurel32         if (initrd_size < 0) {
9856f76b817SAlistair Francis             error_report("could not load initial ram disk '%s'",
9863ef96221SMarcel Apfelbaum                          machine->initrd_filename);
9871db09b84Saurel32             exit(1);
9881db09b84Saurel32         }
989528e536eSAlexander Graf 
990528e536eSAlexander Graf         cur_base = initrd_base + initrd_size;
9911db09b84Saurel32     }
9921db09b84Saurel32 
9933812c71fSAlexander Graf     /*
9943812c71fSAlexander Graf      * Smart firmware defaults ahead!
9953812c71fSAlexander Graf      *
9963812c71fSAlexander Graf      * We follow the following table to select which payload we execute.
9973812c71fSAlexander Graf      *
9983812c71fSAlexander Graf      *  -kernel | -bios | payload
9993812c71fSAlexander Graf      * ---------+-------+---------
10003812c71fSAlexander Graf      *     N    |   Y   | u-boot
10013812c71fSAlexander Graf      *     N    |   N   | u-boot
10023812c71fSAlexander Graf      *     Y    |   Y   | u-boot
10033812c71fSAlexander Graf      *     Y    |   N   | kernel
10043812c71fSAlexander Graf      *
10053812c71fSAlexander Graf      * This ensures backwards compatibility with how we used to expose
10063812c71fSAlexander Graf      * -kernel to users but allows them to run through u-boot as well.
10073812c71fSAlexander Graf      */
10083812c71fSAlexander Graf     if (bios_name == NULL) {
10093ef96221SMarcel Apfelbaum         if (machine->kernel_filename) {
10103812c71fSAlexander Graf             bios_name = machine->kernel_filename;
10113812c71fSAlexander Graf         } else {
10123812c71fSAlexander Graf             bios_name = "u-boot.e500";
10133812c71fSAlexander Graf         }
10143812c71fSAlexander Graf     }
10153812c71fSAlexander Graf     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
10163812c71fSAlexander Graf 
10173812c71fSAlexander Graf     bios_size = load_elf(filename, NULL, NULL, &bios_entry, &loadaddr, NULL,
10187ef295eaSPeter Crosthwaite                          1, PPC_ELF_MACHINE, 0, 0);
10193812c71fSAlexander Graf     if (bios_size < 0) {
10203812c71fSAlexander Graf         /*
10213812c71fSAlexander Graf          * Hrm. No ELF image? Try a uImage, maybe someone is giving us an
10223812c71fSAlexander Graf          * ePAPR compliant kernel
10233812c71fSAlexander Graf          */
102425bda50aSMax Filippov         kernel_size = load_uimage(filename, &bios_entry, &loadaddr, NULL,
102525bda50aSMax Filippov                                   NULL, NULL);
10263812c71fSAlexander Graf         if (kernel_size < 0) {
10276f76b817SAlistair Francis             error_report("could not load firmware '%s'", filename);
10283812c71fSAlexander Graf             exit(1);
10293812c71fSAlexander Graf         }
10303812c71fSAlexander Graf     }
1031f19377bfSShannon Zhao     g_free(filename);
10323812c71fSAlexander Graf 
10333812c71fSAlexander Graf     /* Reserve space for dtb */
10343812c71fSAlexander Graf     dt_base = (loadaddr + bios_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
10355c145dacSAlexander Graf 
10363ef96221SMarcel Apfelbaum     dt_size = ppce500_prep_device_tree(machine, params, dt_base,
1037903585deSAlexander Graf                                        initrd_base, initrd_size,
10383812c71fSAlexander Graf                                        kernel_base, kernel_size);
1039cba2026aSAlexander Graf     if (dt_size < 0) {
10406f76b817SAlistair Francis         error_report("couldn't load device tree");
10411db09b84Saurel32         exit(1);
10421db09b84Saurel32     }
1043b8dec144SAlexander Graf     assert(dt_size < DTB_MAX_SIZE);
10441db09b84Saurel32 
1045e61c36d5SAlexander Graf     boot_info = env->load_info;
10463812c71fSAlexander Graf     boot_info->entry = bios_entry;
10473b989d49SAlexander Graf     boot_info->dt_base = dt_base;
1048cba2026aSAlexander Graf     boot_info->dt_size = dt_size;
10491db09b84Saurel32 }
10503eddc1beSBharat Bhushan 
1051d0c2b0d0Sxiaoqiang zhao static void e500_ccsr_initfn(Object *obj)
10523eddc1beSBharat Bhushan {
1053d0c2b0d0Sxiaoqiang zhao     PPCE500CCSRState *ccsr = CCSR(obj);
1054d0c2b0d0Sxiaoqiang zhao     memory_region_init(&ccsr->ccsr_space, obj, "e500-ccsr",
10553eddc1beSBharat Bhushan                        MPC8544_CCSRBAR_SIZE);
10563eddc1beSBharat Bhushan }
10573eddc1beSBharat Bhushan 
10583eddc1beSBharat Bhushan static const TypeInfo e500_ccsr_info = {
10593eddc1beSBharat Bhushan     .name          = TYPE_CCSR,
10603eddc1beSBharat Bhushan     .parent        = TYPE_SYS_BUS_DEVICE,
10613eddc1beSBharat Bhushan     .instance_size = sizeof(PPCE500CCSRState),
1062d0c2b0d0Sxiaoqiang zhao     .instance_init = e500_ccsr_initfn,
10633eddc1beSBharat Bhushan };
10643eddc1beSBharat Bhushan 
10653eddc1beSBharat Bhushan static void e500_register_types(void)
10663eddc1beSBharat Bhushan {
10673eddc1beSBharat Bhushan     type_register_static(&e500_ccsr_info);
10683eddc1beSBharat Bhushan }
10693eddc1beSBharat Bhushan 
10703eddc1beSBharat Bhushan type_init(e500_register_types)
1071