xref: /qemu/hw/ppc/e500.c (revision fdfb7f2cdb2d0ed364a8c8c538d0ece8c464b534)
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"
41*fdfb7f2cSAlexander 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_BASE       0xE0000000ULL
55ed2bc496SAlexander Graf #define MPC8544_CCSRBAR_SIZE       0x00100000ULL
56dffb1dc2SBharat Bhushan #define MPC8544_MPIC_REGS_OFFSET   0x40000ULL
57a911b7a9SAlexander Graf #define MPC8544_MSI_REGS_OFFSET   0x41600ULL
58dffb1dc2SBharat Bhushan #define MPC8544_SERIAL0_REGS_OFFSET 0x4500ULL
59dffb1dc2SBharat Bhushan #define MPC8544_SERIAL1_REGS_OFFSET 0x4600ULL
60dffb1dc2SBharat Bhushan #define MPC8544_PCI_REGS_OFFSET    0x8000ULL
61dffb1dc2SBharat Bhushan #define MPC8544_PCI_REGS_BASE      (MPC8544_CCSRBAR_BASE + \
62dffb1dc2SBharat Bhushan                                     MPC8544_PCI_REGS_OFFSET)
63ed2bc496SAlexander Graf #define MPC8544_PCI_REGS_SIZE      0x1000ULL
64ed2bc496SAlexander Graf #define MPC8544_PCI_IO             0xE1000000ULL
65dffb1dc2SBharat Bhushan #define MPC8544_UTIL_OFFSET        0xe0000ULL
66ed2bc496SAlexander Graf #define MPC8544_SPIN_BASE          0xEF000000ULL
67b88e77f4SAlexander Graf #define MPC8XXX_GPIO_OFFSET        0x000FF000ULL
68b88e77f4SAlexander Graf #define MPC8XXX_GPIO_IRQ           43
691db09b84Saurel32 
703b989d49SAlexander Graf struct boot_info
713b989d49SAlexander Graf {
723b989d49SAlexander Graf     uint32_t dt_base;
73cba2026aSAlexander Graf     uint32_t dt_size;
743b989d49SAlexander Graf     uint32_t entry;
753b989d49SAlexander Graf };
763b989d49SAlexander Graf 
77347dd79dSAlexander Graf static uint32_t *pci_map_create(void *fdt, uint32_t mpic, int first_slot,
78347dd79dSAlexander Graf                                 int nr_slots, int *len)
790dbc0798SAlexander Graf {
80347dd79dSAlexander Graf     int i = 0;
81347dd79dSAlexander Graf     int slot;
82347dd79dSAlexander Graf     int pci_irq;
839e2c1298SAlexander Graf     int host_irq;
84347dd79dSAlexander Graf     int last_slot = first_slot + nr_slots;
85347dd79dSAlexander Graf     uint32_t *pci_map;
860dbc0798SAlexander Graf 
87347dd79dSAlexander Graf     *len = nr_slots * 4 * 7 * sizeof(uint32_t);
88347dd79dSAlexander Graf     pci_map = g_malloc(*len);
89347dd79dSAlexander Graf 
90347dd79dSAlexander Graf     for (slot = first_slot; slot < last_slot; slot++) {
91347dd79dSAlexander Graf         for (pci_irq = 0; pci_irq < 4; pci_irq++) {
92347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(slot << 11);
93347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(0x0);
94347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(0x0);
95347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(pci_irq + 1);
96347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(mpic);
979e2c1298SAlexander Graf             host_irq = ppce500_pci_map_irq_slot(slot, pci_irq);
989e2c1298SAlexander Graf             pci_map[i++] = cpu_to_be32(host_irq + 1);
99347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(0x1);
1000dbc0798SAlexander Graf         }
1010dbc0798SAlexander Graf     }
1020dbc0798SAlexander Graf 
103347dd79dSAlexander Graf     assert((i * sizeof(uint32_t)) == *len);
104347dd79dSAlexander Graf 
105347dd79dSAlexander Graf     return pci_map;
106347dd79dSAlexander Graf }
107347dd79dSAlexander Graf 
108a053a7ceSAlexander Graf static void dt_serial_create(void *fdt, unsigned long long offset,
109a053a7ceSAlexander Graf                              const char *soc, const char *mpic,
110a053a7ceSAlexander Graf                              const char *alias, int idx, bool defcon)
111a053a7ceSAlexander Graf {
112a053a7ceSAlexander Graf     char ser[128];
113a053a7ceSAlexander Graf 
114a053a7ceSAlexander Graf     snprintf(ser, sizeof(ser), "%s/serial@%llx", soc, offset);
1155a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, ser);
1165a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, ser, "device_type", "serial");
1175a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, ser, "compatible", "ns16550");
1185a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, ser, "reg", offset, 0x100);
1195a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, ser, "cell-index", idx);
1205a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, ser, "clock-frequency", 0);
1215a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, ser, "interrupts", 42, 2);
1225a4348d1SPeter Crosthwaite     qemu_fdt_setprop_phandle(fdt, ser, "interrupt-parent", mpic);
1235a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, "/aliases", alias, ser);
124a053a7ceSAlexander Graf 
125a053a7ceSAlexander Graf     if (defcon) {
1265a4348d1SPeter Crosthwaite         qemu_fdt_setprop_string(fdt, "/chosen", "linux,stdout-path", ser);
127a053a7ceSAlexander Graf     }
128a053a7ceSAlexander Graf }
129a053a7ceSAlexander Graf 
130b88e77f4SAlexander Graf static void create_dt_mpc8xxx_gpio(void *fdt, const char *soc, const char *mpic)
131b88e77f4SAlexander Graf {
132b88e77f4SAlexander Graf     hwaddr mmio0 = MPC8XXX_GPIO_OFFSET;
133b88e77f4SAlexander Graf     int irq0 = MPC8XXX_GPIO_IRQ;
134b88e77f4SAlexander Graf     gchar *node = g_strdup_printf("%s/gpio@%"PRIx64, soc, mmio0);
135016f7758SAlexander Graf     gchar *poweroff = g_strdup_printf("%s/power-off", soc);
136016f7758SAlexander Graf     int gpio_ph;
137b88e77f4SAlexander Graf 
138b88e77f4SAlexander Graf     qemu_fdt_add_subnode(fdt, node);
139b88e77f4SAlexander Graf     qemu_fdt_setprop_string(fdt, node, "compatible", "fsl,qoriq-gpio");
140b88e77f4SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "reg", mmio0, 0x1000);
141b88e77f4SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "interrupts", irq0, 0x2);
142b88e77f4SAlexander Graf     qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", mpic);
143b88e77f4SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "#gpio-cells", 2);
144b88e77f4SAlexander Graf     qemu_fdt_setprop(fdt, node, "gpio-controller", NULL, 0);
145016f7758SAlexander Graf     gpio_ph = qemu_fdt_alloc_phandle(fdt);
146016f7758SAlexander Graf     qemu_fdt_setprop_cell(fdt, node, "phandle", gpio_ph);
147016f7758SAlexander Graf     qemu_fdt_setprop_cell(fdt, node, "linux,phandle", gpio_ph);
148016f7758SAlexander Graf 
149016f7758SAlexander Graf     /* Power Off Pin */
150016f7758SAlexander Graf     qemu_fdt_add_subnode(fdt, poweroff);
151016f7758SAlexander Graf     qemu_fdt_setprop_string(fdt, poweroff, "compatible", "gpio-poweroff");
152016f7758SAlexander Graf     qemu_fdt_setprop_cells(fdt, poweroff, "gpios", gpio_ph, 0, 0);
153b88e77f4SAlexander Graf 
154b88e77f4SAlexander Graf     g_free(node);
155016f7758SAlexander Graf     g_free(poweroff);
156b88e77f4SAlexander Graf }
157b88e77f4SAlexander Graf 
158f7087343SAlexander Graf typedef struct PlatformDevtreeData {
159f7087343SAlexander Graf     void *fdt;
160f7087343SAlexander Graf     const char *mpic;
161f7087343SAlexander Graf     int irq_start;
162f7087343SAlexander Graf     const char *node;
163f7087343SAlexander Graf     PlatformBusDevice *pbus;
164f7087343SAlexander Graf } PlatformDevtreeData;
165f7087343SAlexander Graf 
166*fdfb7f2cSAlexander Graf static int create_devtree_etsec(SysBusDevice *sbdev, PlatformDevtreeData *data)
167*fdfb7f2cSAlexander Graf {
168*fdfb7f2cSAlexander Graf     eTSEC *etsec = ETSEC_COMMON(sbdev);
169*fdfb7f2cSAlexander Graf     PlatformBusDevice *pbus = data->pbus;
170*fdfb7f2cSAlexander Graf     hwaddr mmio0 = platform_bus_get_mmio_addr(pbus, sbdev, 0);
171*fdfb7f2cSAlexander Graf     int irq0 = platform_bus_get_irqn(pbus, sbdev, 0);
172*fdfb7f2cSAlexander Graf     int irq1 = platform_bus_get_irqn(pbus, sbdev, 1);
173*fdfb7f2cSAlexander Graf     int irq2 = platform_bus_get_irqn(pbus, sbdev, 2);
174*fdfb7f2cSAlexander Graf     gchar *node = g_strdup_printf("/platform/ethernet@%"PRIx64, mmio0);
175*fdfb7f2cSAlexander Graf     gchar *group = g_strdup_printf("%s/queue-group", node);
176*fdfb7f2cSAlexander Graf     void *fdt = data->fdt;
177*fdfb7f2cSAlexander Graf 
178*fdfb7f2cSAlexander Graf     assert((int64_t)mmio0 >= 0);
179*fdfb7f2cSAlexander Graf     assert(irq0 >= 0);
180*fdfb7f2cSAlexander Graf     assert(irq1 >= 0);
181*fdfb7f2cSAlexander Graf     assert(irq2 >= 0);
182*fdfb7f2cSAlexander Graf 
183*fdfb7f2cSAlexander Graf     qemu_fdt_add_subnode(fdt, node);
184*fdfb7f2cSAlexander Graf     qemu_fdt_setprop_string(fdt, node, "device_type", "network");
185*fdfb7f2cSAlexander Graf     qemu_fdt_setprop_string(fdt, node, "compatible", "fsl,etsec2");
186*fdfb7f2cSAlexander Graf     qemu_fdt_setprop_string(fdt, node, "model", "eTSEC");
187*fdfb7f2cSAlexander Graf     qemu_fdt_setprop(fdt, node, "local-mac-address", etsec->conf.macaddr.a, 6);
188*fdfb7f2cSAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "fixed-link", 0, 1, 1000, 0, 0);
189*fdfb7f2cSAlexander Graf 
190*fdfb7f2cSAlexander Graf     qemu_fdt_add_subnode(fdt, group);
191*fdfb7f2cSAlexander Graf     qemu_fdt_setprop_cells(fdt, group, "reg", mmio0, 0x1000);
192*fdfb7f2cSAlexander Graf     qemu_fdt_setprop_cells(fdt, group, "interrupts",
193*fdfb7f2cSAlexander Graf         data->irq_start + irq0, 0x2,
194*fdfb7f2cSAlexander Graf         data->irq_start + irq1, 0x2,
195*fdfb7f2cSAlexander Graf         data->irq_start + irq2, 0x2);
196*fdfb7f2cSAlexander Graf 
197*fdfb7f2cSAlexander Graf     g_free(node);
198*fdfb7f2cSAlexander Graf     g_free(group);
199*fdfb7f2cSAlexander Graf 
200*fdfb7f2cSAlexander Graf     return 0;
201*fdfb7f2cSAlexander Graf }
202*fdfb7f2cSAlexander Graf 
203f7087343SAlexander Graf static int sysbus_device_create_devtree(SysBusDevice *sbdev, void *opaque)
204f7087343SAlexander Graf {
205f7087343SAlexander Graf     PlatformDevtreeData *data = opaque;
206f7087343SAlexander Graf     bool matched = false;
207f7087343SAlexander Graf 
208*fdfb7f2cSAlexander Graf     if (object_dynamic_cast(OBJECT(sbdev), TYPE_ETSEC_COMMON)) {
209*fdfb7f2cSAlexander Graf         create_devtree_etsec(sbdev, data);
210*fdfb7f2cSAlexander Graf         matched = true;
211*fdfb7f2cSAlexander Graf     }
212*fdfb7f2cSAlexander Graf 
213f7087343SAlexander Graf     if (!matched) {
214f7087343SAlexander Graf         error_report("Device %s is not supported by this machine yet.",
215f7087343SAlexander Graf                      qdev_fw_name(DEVICE(sbdev)));
216f7087343SAlexander Graf         exit(1);
217f7087343SAlexander Graf     }
218f7087343SAlexander Graf 
219f7087343SAlexander Graf     return 0;
220f7087343SAlexander Graf }
221f7087343SAlexander Graf 
222f7087343SAlexander Graf static void platform_bus_create_devtree(PPCE500Params *params, void *fdt,
223f7087343SAlexander Graf                                         const char *mpic)
224f7087343SAlexander Graf {
225f7087343SAlexander Graf     gchar *node = g_strdup_printf("/platform@%"PRIx64, params->platform_bus_base);
226f7087343SAlexander Graf     const char platcomp[] = "qemu,platform\0simple-bus";
227f7087343SAlexander Graf     uint64_t addr = params->platform_bus_base;
228f7087343SAlexander Graf     uint64_t size = params->platform_bus_size;
229f7087343SAlexander Graf     int irq_start = params->platform_bus_first_irq;
230f7087343SAlexander Graf     PlatformBusDevice *pbus;
231f7087343SAlexander Graf     DeviceState *dev;
232f7087343SAlexander Graf 
233f7087343SAlexander Graf     /* Create a /platform node that we can put all devices into */
234f7087343SAlexander Graf 
235f7087343SAlexander Graf     qemu_fdt_add_subnode(fdt, node);
236f7087343SAlexander Graf     qemu_fdt_setprop(fdt, node, "compatible", platcomp, sizeof(platcomp));
237f7087343SAlexander Graf 
238f7087343SAlexander Graf     /* Our platform bus region is less than 32bit big, so 1 cell is enough for
239f7087343SAlexander Graf        address and size */
240f7087343SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "#size-cells", 1);
241f7087343SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "#address-cells", 1);
242f7087343SAlexander Graf     qemu_fdt_setprop_cells(fdt, node, "ranges", 0, addr >> 32, addr, size);
243f7087343SAlexander Graf 
244f7087343SAlexander Graf     qemu_fdt_setprop_phandle(fdt, node, "interrupt-parent", mpic);
245f7087343SAlexander Graf 
246f7087343SAlexander Graf     dev = qdev_find_recursive(sysbus_get_default(), TYPE_PLATFORM_BUS_DEVICE);
247f7087343SAlexander Graf     pbus = PLATFORM_BUS_DEVICE(dev);
248f7087343SAlexander Graf 
249f7087343SAlexander Graf     /* We can only create dt nodes for dynamic devices when they're ready */
250f7087343SAlexander Graf     if (pbus->done_gathering) {
251f7087343SAlexander Graf         PlatformDevtreeData data = {
252f7087343SAlexander Graf             .fdt = fdt,
253f7087343SAlexander Graf             .mpic = mpic,
254f7087343SAlexander Graf             .irq_start = irq_start,
255f7087343SAlexander Graf             .node = node,
256f7087343SAlexander Graf             .pbus = pbus,
257f7087343SAlexander Graf         };
258f7087343SAlexander Graf 
259f7087343SAlexander Graf         /* Loop through all dynamic sysbus devices and create nodes for them */
260f7087343SAlexander Graf         foreach_dynamic_sysbus_device(sysbus_device_create_devtree, &data);
261f7087343SAlexander Graf     }
262f7087343SAlexander Graf 
263f7087343SAlexander Graf     g_free(node);
264f7087343SAlexander Graf }
265f7087343SAlexander Graf 
2663ef96221SMarcel Apfelbaum static int ppce500_load_device_tree(MachineState *machine,
267e6eaabebSScott Wood                                     PPCE500Params *params,
268a8170e5eSAvi Kivity                                     hwaddr addr,
269a8170e5eSAvi Kivity                                     hwaddr initrd_base,
27028290f37SAlexander Graf                                     hwaddr initrd_size,
271903585deSAlexander Graf                                     hwaddr kernel_base,
272903585deSAlexander Graf                                     hwaddr kernel_size,
27328290f37SAlexander Graf                                     bool dry_run)
2741db09b84Saurel32 {
27528290f37SAlexander Graf     CPUPPCState *env = first_cpu->env_ptr;
276dbf916d8SAurelien Jarno     int ret = -1;
2773ef96221SMarcel Apfelbaum     uint64_t mem_reg_property[] = { 0, cpu_to_be64(machine->ram_size) };
2787ec632b4Spbrook     int fdt_size;
279dbf916d8SAurelien Jarno     void *fdt;
2805de6b46dSAlexander Graf     uint8_t hypercall[16];
281911d6e7aSAlexander Graf     uint32_t clock_freq = 400000000;
282911d6e7aSAlexander Graf     uint32_t tb_freq = 400000000;
283621d05e3SAlexander Graf     int i;
284ebb9518aSAlexander Graf     char compatible_sb[] = "fsl,mpc8544-immr\0simple-bus";
2855da96624SAlexander Graf     char soc[128];
28619ac9deaSAlexander Graf     char mpic[128];
28719ac9deaSAlexander Graf     uint32_t mpic_ph;
288a911b7a9SAlexander Graf     uint32_t msi_ph;
289f5038483SAlexander Graf     char gutil[128];
2900dbc0798SAlexander Graf     char pci[128];
291a911b7a9SAlexander Graf     char msi[128];
292347dd79dSAlexander Graf     uint32_t *pci_map = NULL;
293347dd79dSAlexander Graf     int len;
2943627757eSAlexander Graf     uint32_t pci_ranges[14] =
2953627757eSAlexander Graf         {
2963627757eSAlexander Graf             0x2000000, 0x0, 0xc0000000,
2973627757eSAlexander Graf             0x0, 0xc0000000,
2983627757eSAlexander Graf             0x0, 0x20000000,
2993627757eSAlexander Graf 
3003627757eSAlexander Graf             0x1000000, 0x0, 0x0,
3013627757eSAlexander Graf             0x0, 0xe1000000,
3023627757eSAlexander Graf             0x0, 0x10000,
3033627757eSAlexander Graf         };
3042ff3de68SMarkus Armbruster     QemuOpts *machine_opts = qemu_get_machine_opts();
3052ff3de68SMarkus Armbruster     const char *dtb_file = qemu_opt_get(machine_opts, "dtb");
3062ff3de68SMarkus Armbruster     const char *toplevel_compat = qemu_opt_get(machine_opts, "dt_compatible");
307d1b93565SAlexander Graf 
308d1b93565SAlexander Graf     if (dtb_file) {
309d1b93565SAlexander Graf         char *filename;
310d1b93565SAlexander Graf         filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_file);
311d1b93565SAlexander Graf         if (!filename) {
312d1b93565SAlexander Graf             goto out;
313d1b93565SAlexander Graf         }
314d1b93565SAlexander Graf 
315d1b93565SAlexander Graf         fdt = load_device_tree(filename, &fdt_size);
316d1b93565SAlexander Graf         if (!fdt) {
317d1b93565SAlexander Graf             goto out;
318d1b93565SAlexander Graf         }
319d1b93565SAlexander Graf         goto done;
320d1b93565SAlexander Graf     }
3211db09b84Saurel32 
3222636fcb6SAlexander Graf     fdt = create_device_tree(&fdt_size);
3235cea8590SPaul Brook     if (fdt == NULL) {
3245cea8590SPaul Brook         goto out;
3255cea8590SPaul Brook     }
3261db09b84Saurel32 
3271db09b84Saurel32     /* Manipulate device tree in memory. */
3285a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 2);
3295a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 2);
33051b852b7SAlexander Graf 
3315a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, "/memory");
3325a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, "/memory", "device_type", "memory");
3335a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, "/memory", "reg", mem_reg_property,
3341db09b84Saurel32                      sizeof(mem_reg_property));
3351db09b84Saurel32 
3365a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, "/chosen");
3373b989d49SAlexander Graf     if (initrd_size) {
3385a4348d1SPeter Crosthwaite         ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start",
3391db09b84Saurel32                                     initrd_base);
3403b989d49SAlexander Graf         if (ret < 0) {
3411db09b84Saurel32             fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
3423b989d49SAlexander Graf         }
3431db09b84Saurel32 
3445a4348d1SPeter Crosthwaite         ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
3451db09b84Saurel32                                     (initrd_base + initrd_size));
3463b989d49SAlexander Graf         if (ret < 0) {
3471db09b84Saurel32             fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
3483b989d49SAlexander Graf         }
349903585deSAlexander Graf 
350903585deSAlexander Graf     }
351903585deSAlexander Graf 
352903585deSAlexander Graf     if (kernel_base != -1ULL) {
353903585deSAlexander Graf         qemu_fdt_setprop_cells(fdt, "/chosen", "qemu,boot-kernel",
354903585deSAlexander Graf                                      kernel_base >> 32, kernel_base,
355903585deSAlexander Graf                                      kernel_size >> 32, kernel_size);
3563b989d49SAlexander Graf     }
3571db09b84Saurel32 
3585a4348d1SPeter Crosthwaite     ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
3593ef96221SMarcel Apfelbaum                                       machine->kernel_cmdline);
3601db09b84Saurel32     if (ret < 0)
3611db09b84Saurel32         fprintf(stderr, "couldn't set /chosen/bootargs\n");
3621db09b84Saurel32 
3631db09b84Saurel32     if (kvm_enabled()) {
364911d6e7aSAlexander Graf         /* Read out host's frequencies */
365911d6e7aSAlexander Graf         clock_freq = kvmppc_get_clockfreq();
366911d6e7aSAlexander Graf         tb_freq = kvmppc_get_tbfreq();
3675de6b46dSAlexander Graf 
3685de6b46dSAlexander Graf         /* indicate KVM hypercall interface */
3695a4348d1SPeter Crosthwaite         qemu_fdt_add_subnode(fdt, "/hypervisor");
3705a4348d1SPeter Crosthwaite         qemu_fdt_setprop_string(fdt, "/hypervisor", "compatible",
3715de6b46dSAlexander Graf                                 "linux,kvm");
3725de6b46dSAlexander Graf         kvmppc_get_hypercall(env, hypercall, sizeof(hypercall));
3735a4348d1SPeter Crosthwaite         qemu_fdt_setprop(fdt, "/hypervisor", "hcall-instructions",
3745de6b46dSAlexander Graf                          hypercall, sizeof(hypercall));
3751a61a9aeSStuart Yoder         /* if KVM supports the idle hcall, set property indicating this */
3761a61a9aeSStuart Yoder         if (kvmppc_get_hasidle(env)) {
3775a4348d1SPeter Crosthwaite             qemu_fdt_setprop(fdt, "/hypervisor", "has-idle", NULL, 0);
3781a61a9aeSStuart Yoder         }
3791db09b84Saurel32     }
3801db09b84Saurel32 
381625e665bSAlexander Graf     /* Create CPU nodes */
3825a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, "/cpus");
3835a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 1);
3845a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0);
385625e665bSAlexander Graf 
3861e3debf0SAlexander Graf     /* We need to generate the cpu nodes in reverse order, so Linux can pick
3871e3debf0SAlexander Graf        the first node as boot node and be happy */
3881e3debf0SAlexander Graf     for (i = smp_cpus - 1; i >= 0; i--) {
389440c8152SAndreas Färber         CPUState *cpu;
3900f20ba62SAlexey Kardashevskiy         PowerPCCPU *pcpu;
391621d05e3SAlexander Graf         char cpu_name[128];
3921d2e5c52SAlexander Graf         uint64_t cpu_release_addr = MPC8544_SPIN_BASE + (i * 0x20);
39310f25a46SAlexander Graf 
394440c8152SAndreas Färber         cpu = qemu_get_cpu(i);
39555e5c285SAndreas Färber         if (cpu == NULL) {
3961e3debf0SAlexander Graf             continue;
3971e3debf0SAlexander Graf         }
398440c8152SAndreas Färber         env = cpu->env_ptr;
3990f20ba62SAlexey Kardashevskiy         pcpu = POWERPC_CPU(cpu);
4001e3debf0SAlexander Graf 
40155e5c285SAndreas Färber         snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x",
4020f20ba62SAlexey Kardashevskiy                  ppc_get_vcpu_dt_id(pcpu));
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");
4070f20ba62SAlexey Kardashevskiy         qemu_fdt_setprop_cell(fdt, cpu_name, "reg",
4080f20ba62SAlexey Kardashevskiy                               ppc_get_vcpu_dt_id(pcpu));
4095a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-line-size",
4101e3debf0SAlexander Graf                               env->dcache_line_size);
4115a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-line-size",
4121e3debf0SAlexander Graf                               env->icache_line_size);
4135a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-size", 0x8000);
4145a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-size", 0x8000);
4155a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "bus-frequency", 0);
41655e5c285SAndreas Färber         if (cpu->cpu_index) {
4175a4348d1SPeter Crosthwaite             qemu_fdt_setprop_string(fdt, cpu_name, "status", "disabled");
4185a4348d1SPeter Crosthwaite             qemu_fdt_setprop_string(fdt, cpu_name, "enable-method",
4195a4348d1SPeter Crosthwaite                                     "spin-table");
4205a4348d1SPeter Crosthwaite             qemu_fdt_setprop_u64(fdt, cpu_name, "cpu-release-addr",
4211d2e5c52SAlexander Graf                                  cpu_release_addr);
4221e3debf0SAlexander Graf         } else {
4235a4348d1SPeter Crosthwaite             qemu_fdt_setprop_string(fdt, cpu_name, "status", "okay");
4241e3debf0SAlexander Graf         }
4251db09b84Saurel32     }
4261db09b84Saurel32 
4275a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, "/aliases");
4285da96624SAlexander Graf     /* XXX These should go into their respective devices' code */
429ed2bc496SAlexander Graf     snprintf(soc, sizeof(soc), "/soc@%llx", MPC8544_CCSRBAR_BASE);
4305a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, soc);
4315a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, soc, "device_type", "soc");
4325a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, soc, "compatible", compatible_sb,
433ebb9518aSAlexander Graf                      sizeof(compatible_sb));
4345a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, soc, "#address-cells", 1);
4355a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, soc, "#size-cells", 1);
4365a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, soc, "ranges", 0x0,
4373627757eSAlexander Graf                            MPC8544_CCSRBAR_BASE >> 32, MPC8544_CCSRBAR_BASE,
4385da96624SAlexander Graf                            MPC8544_CCSRBAR_SIZE);
4395da96624SAlexander Graf     /* XXX should contain a reasonable value */
4405a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, soc, "bus-frequency", 0);
4415da96624SAlexander Graf 
442dffb1dc2SBharat Bhushan     snprintf(mpic, sizeof(mpic), "%s/pic@%llx", soc, MPC8544_MPIC_REGS_OFFSET);
4435a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, mpic);
4445a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, mpic, "device_type", "open-pic");
4455a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, mpic, "compatible", "fsl,mpic");
4465a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_OFFSET,
447dffb1dc2SBharat Bhushan                            0x40000);
4485a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, mpic, "#address-cells", 0);
4495a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, mpic, "#interrupt-cells", 2);
4505a4348d1SPeter Crosthwaite     mpic_ph = qemu_fdt_alloc_phandle(fdt);
4515a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, mpic, "phandle", mpic_ph);
4525a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, mpic, "linux,phandle", mpic_ph);
4535a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, mpic, "interrupt-controller", NULL, 0);
45419ac9deaSAlexander Graf 
4550cfc6e8dSAlexander Graf     /*
4560cfc6e8dSAlexander Graf      * We have to generate ser1 first, because Linux takes the first
4570cfc6e8dSAlexander Graf      * device it finds in the dt as serial output device. And we generate
4580cfc6e8dSAlexander Graf      * devices in reverse order to the dt.
4590cfc6e8dSAlexander Graf      */
46079c0ff2cSAlexander Graf     if (serial_hds[1]) {
461dffb1dc2SBharat Bhushan         dt_serial_create(fdt, MPC8544_SERIAL1_REGS_OFFSET,
462a053a7ceSAlexander Graf                          soc, mpic, "serial1", 1, false);
46379c0ff2cSAlexander Graf     }
46479c0ff2cSAlexander Graf 
46579c0ff2cSAlexander Graf     if (serial_hds[0]) {
466dffb1dc2SBharat Bhushan         dt_serial_create(fdt, MPC8544_SERIAL0_REGS_OFFSET,
467a053a7ceSAlexander Graf                          soc, mpic, "serial0", 0, true);
46879c0ff2cSAlexander Graf     }
4690cfc6e8dSAlexander Graf 
470ed2bc496SAlexander Graf     snprintf(gutil, sizeof(gutil), "%s/global-utilities@%llx", soc,
471dffb1dc2SBharat Bhushan              MPC8544_UTIL_OFFSET);
4725a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, gutil);
4735a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, gutil, "compatible", "fsl,mpc8544-guts");
4745a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, gutil, "reg", MPC8544_UTIL_OFFSET, 0x1000);
4755a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, gutil, "fsl,has-rstcr", NULL, 0);
476f5038483SAlexander Graf 
477a911b7a9SAlexander Graf     snprintf(msi, sizeof(msi), "/%s/msi@%llx", soc, MPC8544_MSI_REGS_OFFSET);
4785a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, msi);
4795a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, msi, "compatible", "fsl,mpic-msi");
4805a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, msi, "reg", MPC8544_MSI_REGS_OFFSET, 0x200);
4815a4348d1SPeter Crosthwaite     msi_ph = qemu_fdt_alloc_phandle(fdt);
4825a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, msi, "msi-available-ranges", 0x0, 0x100);
4835a4348d1SPeter Crosthwaite     qemu_fdt_setprop_phandle(fdt, msi, "interrupt-parent", mpic);
4845a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, msi, "interrupts",
485a911b7a9SAlexander Graf         0xe0, 0x0,
486a911b7a9SAlexander Graf         0xe1, 0x0,
487a911b7a9SAlexander Graf         0xe2, 0x0,
488a911b7a9SAlexander Graf         0xe3, 0x0,
489a911b7a9SAlexander Graf         0xe4, 0x0,
490a911b7a9SAlexander Graf         0xe5, 0x0,
491a911b7a9SAlexander Graf         0xe6, 0x0,
492a911b7a9SAlexander Graf         0xe7, 0x0);
4935a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, msi, "phandle", msi_ph);
4945a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, msi, "linux,phandle", msi_ph);
495a911b7a9SAlexander Graf 
496ed2bc496SAlexander Graf     snprintf(pci, sizeof(pci), "/pci@%llx", MPC8544_PCI_REGS_BASE);
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));
5155a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, pci, "reg", MPC8544_PCI_REGS_BASE >> 32,
5163627757eSAlexander Graf                            MPC8544_PCI_REGS_BASE, 0, 0x1000);
5175a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "clock-frequency", 66666666);
5185a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "#interrupt-cells", 1);
5195a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "#size-cells", 2);
5205a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "#address-cells", 3);
5215a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, "/aliases", "pci0", pci);
5220dbc0798SAlexander Graf 
523b88e77f4SAlexander Graf     if (params->has_mpc8xxx_gpio) {
524b88e77f4SAlexander Graf         create_dt_mpc8xxx_gpio(fdt, soc, mpic);
525b88e77f4SAlexander Graf     }
526b88e77f4SAlexander Graf 
527f7087343SAlexander Graf     if (params->has_platform_bus) {
528f7087343SAlexander Graf         platform_bus_create_devtree(params, fdt, mpic);
529f7087343SAlexander Graf     }
530f7087343SAlexander Graf 
531e6eaabebSScott Wood     params->fixup_devtree(params, fdt);
532e6eaabebSScott Wood 
533e6eaabebSScott Wood     if (toplevel_compat) {
5345a4348d1SPeter Crosthwaite         qemu_fdt_setprop(fdt, "/", "compatible", toplevel_compat,
535e6eaabebSScott Wood                          strlen(toplevel_compat) + 1);
536e6eaabebSScott Wood     }
537e6eaabebSScott Wood 
538d1b93565SAlexander Graf done:
53928290f37SAlexander Graf     if (!dry_run) {
5405a4348d1SPeter Crosthwaite         qemu_fdt_dumpdtb(fdt, fdt_size);
54128290f37SAlexander Graf         cpu_physical_memory_write(addr, fdt, fdt_size);
542cba2026aSAlexander Graf     }
543cba2026aSAlexander Graf     ret = fdt_size;
5447ec632b4Spbrook 
5451db09b84Saurel32 out:
546347dd79dSAlexander Graf     g_free(pci_map);
5471db09b84Saurel32 
54804088adbSLiu Yu     return ret;
5491db09b84Saurel32 }
5501db09b84Saurel32 
55128290f37SAlexander Graf typedef struct DeviceTreeParams {
5523ef96221SMarcel Apfelbaum     MachineState *machine;
55328290f37SAlexander Graf     PPCE500Params params;
55428290f37SAlexander Graf     hwaddr addr;
55528290f37SAlexander Graf     hwaddr initrd_base;
55628290f37SAlexander Graf     hwaddr initrd_size;
557903585deSAlexander Graf     hwaddr kernel_base;
558903585deSAlexander Graf     hwaddr kernel_size;
559f7087343SAlexander Graf     Notifier notifier;
56028290f37SAlexander Graf } DeviceTreeParams;
56128290f37SAlexander Graf 
56228290f37SAlexander Graf static void ppce500_reset_device_tree(void *opaque)
56328290f37SAlexander Graf {
56428290f37SAlexander Graf     DeviceTreeParams *p = opaque;
5653812c71fSAlexander Graf     ppce500_load_device_tree(p->machine, &p->params, p->addr, p->initrd_base,
566903585deSAlexander Graf                              p->initrd_size, p->kernel_base, p->kernel_size,
567903585deSAlexander Graf                              false);
56828290f37SAlexander Graf }
56928290f37SAlexander Graf 
570f7087343SAlexander Graf static void ppce500_init_notify(Notifier *notifier, void *data)
571f7087343SAlexander Graf {
572f7087343SAlexander Graf     DeviceTreeParams *p = container_of(notifier, DeviceTreeParams, notifier);
573f7087343SAlexander Graf     ppce500_reset_device_tree(p);
574f7087343SAlexander Graf }
575f7087343SAlexander Graf 
5763ef96221SMarcel Apfelbaum static int ppce500_prep_device_tree(MachineState *machine,
57728290f37SAlexander Graf                                     PPCE500Params *params,
57828290f37SAlexander Graf                                     hwaddr addr,
57928290f37SAlexander Graf                                     hwaddr initrd_base,
580903585deSAlexander Graf                                     hwaddr initrd_size,
581903585deSAlexander Graf                                     hwaddr kernel_base,
582903585deSAlexander Graf                                     hwaddr kernel_size)
58328290f37SAlexander Graf {
58428290f37SAlexander Graf     DeviceTreeParams *p = g_new(DeviceTreeParams, 1);
5853ef96221SMarcel Apfelbaum     p->machine = machine;
58628290f37SAlexander Graf     p->params = *params;
58728290f37SAlexander Graf     p->addr = addr;
58828290f37SAlexander Graf     p->initrd_base = initrd_base;
58928290f37SAlexander Graf     p->initrd_size = initrd_size;
590903585deSAlexander Graf     p->kernel_base = kernel_base;
591903585deSAlexander Graf     p->kernel_size = kernel_size;
59228290f37SAlexander Graf 
59328290f37SAlexander Graf     qemu_register_reset(ppce500_reset_device_tree, p);
594f7087343SAlexander Graf     p->notifier.notify = ppce500_init_notify;
595f7087343SAlexander Graf     qemu_add_machine_init_done_notifier(&p->notifier);
59628290f37SAlexander Graf 
59728290f37SAlexander Graf     /* Issue the device tree loader once, so that we get the size of the blob */
5983ef96221SMarcel Apfelbaum     return ppce500_load_device_tree(machine, params, addr, initrd_base,
599903585deSAlexander Graf                                     initrd_size, kernel_base, kernel_size,
600903585deSAlexander Graf                                     true);
60128290f37SAlexander Graf }
60228290f37SAlexander Graf 
603cba2026aSAlexander Graf /* Create -kernel TLB entries for BookE.  */
604a8170e5eSAvi Kivity static inline hwaddr booke206_page_size_to_tlb(uint64_t size)
605d1e256feSAlexander Graf {
606cba2026aSAlexander Graf     return 63 - clz64(size >> 10);
607d1e256feSAlexander Graf }
608d1e256feSAlexander Graf 
609cefd3cdbSBharat Bhushan static int booke206_initial_map_tsize(CPUPPCState *env)
6103b989d49SAlexander Graf {
611cba2026aSAlexander Graf     struct boot_info *bi = env->load_info;
612cefd3cdbSBharat Bhushan     hwaddr dt_end;
613cba2026aSAlexander Graf     int ps;
6143b989d49SAlexander Graf 
615cba2026aSAlexander Graf     /* Our initial TLB entry needs to cover everything from 0 to
616cba2026aSAlexander Graf        the device tree top */
617cba2026aSAlexander Graf     dt_end = bi->dt_base + bi->dt_size;
618cba2026aSAlexander Graf     ps = booke206_page_size_to_tlb(dt_end) + 1;
619fb37c302SAlexander Graf     if (ps & 1) {
620fb37c302SAlexander Graf         /* e500v2 can only do even TLB size bits */
621fb37c302SAlexander Graf         ps++;
622fb37c302SAlexander Graf     }
623cefd3cdbSBharat Bhushan     return ps;
624cefd3cdbSBharat Bhushan }
625cefd3cdbSBharat Bhushan 
626cefd3cdbSBharat Bhushan static uint64_t mmubooke_initial_mapsize(CPUPPCState *env)
627cefd3cdbSBharat Bhushan {
628cefd3cdbSBharat Bhushan     int tsize;
629cefd3cdbSBharat Bhushan 
630cefd3cdbSBharat Bhushan     tsize = booke206_initial_map_tsize(env);
631cefd3cdbSBharat Bhushan     return (1ULL << 10 << tsize);
632cefd3cdbSBharat Bhushan }
633cefd3cdbSBharat Bhushan 
634cefd3cdbSBharat Bhushan static void mmubooke_create_initial_mapping(CPUPPCState *env)
635cefd3cdbSBharat Bhushan {
636cefd3cdbSBharat Bhushan     ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0);
637cefd3cdbSBharat Bhushan     hwaddr size;
638cefd3cdbSBharat Bhushan     int ps;
639cefd3cdbSBharat Bhushan 
640cefd3cdbSBharat Bhushan     ps = booke206_initial_map_tsize(env);
641cba2026aSAlexander Graf     size = (ps << MAS1_TSIZE_SHIFT);
642d1e256feSAlexander Graf     tlb->mas1 = MAS1_VALID | size;
643cba2026aSAlexander Graf     tlb->mas2 = 0;
644cba2026aSAlexander Graf     tlb->mas7_3 = 0;
645d1e256feSAlexander Graf     tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
64693dd5e85SScott Wood 
64793dd5e85SScott Wood     env->tlb_dirty = true;
6483b989d49SAlexander Graf }
6493b989d49SAlexander Graf 
650b3305981SScott Wood static void ppce500_cpu_reset_sec(void *opaque)
6515c145dacSAlexander Graf {
65238f92da6SAndreas Färber     PowerPCCPU *cpu = opaque;
653259186a7SAndreas Färber     CPUState *cs = CPU(cpu);
6545c145dacSAlexander Graf 
655259186a7SAndreas Färber     cpu_reset(cs);
6565c145dacSAlexander Graf 
6575c145dacSAlexander Graf     /* Secondary CPU starts in halted state for now. Needs to change when
6585c145dacSAlexander Graf        implementing non-kernel boot. */
659259186a7SAndreas Färber     cs->halted = 1;
66027103424SAndreas Färber     cs->exception_index = EXCP_HLT;
6613b989d49SAlexander Graf }
6623b989d49SAlexander Graf 
663b3305981SScott Wood static void ppce500_cpu_reset(void *opaque)
6643b989d49SAlexander Graf {
66538f92da6SAndreas Färber     PowerPCCPU *cpu = opaque;
666259186a7SAndreas Färber     CPUState *cs = CPU(cpu);
66738f92da6SAndreas Färber     CPUPPCState *env = &cpu->env;
6683b989d49SAlexander Graf     struct boot_info *bi = env->load_info;
6693b989d49SAlexander Graf 
670259186a7SAndreas Färber     cpu_reset(cs);
6713b989d49SAlexander Graf 
6723b989d49SAlexander Graf     /* Set initial guest state. */
673259186a7SAndreas Färber     cs->halted = 0;
6743b989d49SAlexander Graf     env->gpr[1] = (16<<20) - 8;
6753b989d49SAlexander Graf     env->gpr[3] = bi->dt_base;
676cefd3cdbSBharat Bhushan     env->gpr[4] = 0;
677cefd3cdbSBharat Bhushan     env->gpr[5] = 0;
678cefd3cdbSBharat Bhushan     env->gpr[6] = EPAPR_MAGIC;
679cefd3cdbSBharat Bhushan     env->gpr[7] = mmubooke_initial_mapsize(env);
680cefd3cdbSBharat Bhushan     env->gpr[8] = 0;
681cefd3cdbSBharat Bhushan     env->gpr[9] = 0;
6823b989d49SAlexander Graf     env->nip = bi->entry;
683cba2026aSAlexander Graf     mmubooke_create_initial_mapping(env);
6843b989d49SAlexander Graf }
6853b989d49SAlexander Graf 
686d85937e6SScott Wood static DeviceState *ppce500_init_mpic_qemu(PPCE500Params *params,
68782fc73b6SScott Wood                                            qemu_irq **irqs)
68882fc73b6SScott Wood {
68982fc73b6SScott Wood     DeviceState *dev;
69082fc73b6SScott Wood     SysBusDevice *s;
69182fc73b6SScott Wood     int i, j, k;
69282fc73b6SScott Wood 
693e1766344SAndreas Färber     dev = qdev_create(NULL, TYPE_OPENPIC);
69482fc73b6SScott Wood     qdev_prop_set_uint32(dev, "model", params->mpic_version);
695d85937e6SScott Wood     qdev_prop_set_uint32(dev, "nb_cpus", smp_cpus);
696d85937e6SScott Wood 
69782fc73b6SScott Wood     qdev_init_nofail(dev);
69882fc73b6SScott Wood     s = SYS_BUS_DEVICE(dev);
69982fc73b6SScott Wood 
70082fc73b6SScott Wood     k = 0;
70182fc73b6SScott Wood     for (i = 0; i < smp_cpus; i++) {
70282fc73b6SScott Wood         for (j = 0; j < OPENPIC_OUTPUT_NB; j++) {
70382fc73b6SScott Wood             sysbus_connect_irq(s, k++, irqs[i][j]);
70482fc73b6SScott Wood         }
70582fc73b6SScott Wood     }
70682fc73b6SScott Wood 
707d85937e6SScott Wood     return dev;
708d85937e6SScott Wood }
709d85937e6SScott Wood 
710d85937e6SScott Wood static DeviceState *ppce500_init_mpic_kvm(PPCE500Params *params,
711d85937e6SScott Wood                                           qemu_irq **irqs)
712d85937e6SScott Wood {
713d85937e6SScott Wood     DeviceState *dev;
714d85937e6SScott Wood     CPUState *cs;
715d85937e6SScott Wood     int r;
716d85937e6SScott Wood 
717dd49c038SAndreas Färber     dev = qdev_create(NULL, TYPE_KVM_OPENPIC);
718d85937e6SScott Wood     qdev_prop_set_uint32(dev, "model", params->mpic_version);
719d85937e6SScott Wood 
720d85937e6SScott Wood     r = qdev_init(dev);
721d85937e6SScott Wood     if (r) {
722d85937e6SScott Wood         return NULL;
723d85937e6SScott Wood     }
724d85937e6SScott Wood 
725bdc44640SAndreas Färber     CPU_FOREACH(cs) {
726d85937e6SScott Wood         if (kvm_openpic_connect_vcpu(dev, cs)) {
727d85937e6SScott Wood             fprintf(stderr, "%s: failed to connect vcpu to irqchip\n",
728d85937e6SScott Wood                     __func__);
729d85937e6SScott Wood             abort();
730d85937e6SScott Wood         }
731d85937e6SScott Wood     }
732d85937e6SScott Wood 
733d85937e6SScott Wood     return dev;
734d85937e6SScott Wood }
735d85937e6SScott Wood 
736d85937e6SScott Wood static qemu_irq *ppce500_init_mpic(PPCE500Params *params, MemoryRegion *ccsr,
737d85937e6SScott Wood                                    qemu_irq **irqs)
738d85937e6SScott Wood {
739d85937e6SScott Wood     qemu_irq *mpic;
740d85937e6SScott Wood     DeviceState *dev = NULL;
741d85937e6SScott Wood     SysBusDevice *s;
742d85937e6SScott Wood     int i;
743d85937e6SScott Wood 
744aa2ac1daSPeter Crosthwaite     mpic = g_new0(qemu_irq, 256);
745d85937e6SScott Wood 
746d85937e6SScott Wood     if (kvm_enabled()) {
74736ad0e94SMarkus Armbruster         QemuOpts *machine_opts = qemu_get_machine_opts();
74836ad0e94SMarkus Armbruster         bool irqchip_allowed = qemu_opt_get_bool(machine_opts,
749d85937e6SScott Wood                                                 "kernel_irqchip", true);
75036ad0e94SMarkus Armbruster         bool irqchip_required = qemu_opt_get_bool(machine_opts,
751d85937e6SScott Wood                                                   "kernel_irqchip", false);
752d85937e6SScott Wood 
753d85937e6SScott Wood         if (irqchip_allowed) {
754d85937e6SScott Wood             dev = ppce500_init_mpic_kvm(params, irqs);
755d85937e6SScott Wood         }
756d85937e6SScott Wood 
757d85937e6SScott Wood         if (irqchip_required && !dev) {
758d85937e6SScott Wood             fprintf(stderr, "%s: irqchip requested but unavailable\n",
759d85937e6SScott Wood                     __func__);
760d85937e6SScott Wood             abort();
761d85937e6SScott Wood         }
762d85937e6SScott Wood     }
763d85937e6SScott Wood 
764d85937e6SScott Wood     if (!dev) {
765d85937e6SScott Wood         dev = ppce500_init_mpic_qemu(params, irqs);
766d85937e6SScott Wood     }
767d85937e6SScott Wood 
76882fc73b6SScott Wood     for (i = 0; i < 256; i++) {
76982fc73b6SScott Wood         mpic[i] = qdev_get_gpio_in(dev, i);
77082fc73b6SScott Wood     }
77182fc73b6SScott Wood 
772d85937e6SScott Wood     s = SYS_BUS_DEVICE(dev);
77382fc73b6SScott Wood     memory_region_add_subregion(ccsr, MPC8544_MPIC_REGS_OFFSET,
77482fc73b6SScott Wood                                 s->mmio[0].memory);
77582fc73b6SScott Wood 
77682fc73b6SScott Wood     return mpic;
77782fc73b6SScott Wood }
77882fc73b6SScott Wood 
779016f7758SAlexander Graf static void ppce500_power_off(void *opaque, int line, int on)
780016f7758SAlexander Graf {
781016f7758SAlexander Graf     if (on) {
782016f7758SAlexander Graf         qemu_system_shutdown_request();
783016f7758SAlexander Graf     }
784016f7758SAlexander Graf }
785016f7758SAlexander Graf 
7863ef96221SMarcel Apfelbaum void ppce500_init(MachineState *machine, PPCE500Params *params)
7871db09b84Saurel32 {
78839186d8aSRichard Henderson     MemoryRegion *address_space_mem = get_system_memory();
7892646c133SAvi Kivity     MemoryRegion *ram = g_new(MemoryRegion, 1);
7901db09b84Saurel32     PCIBus *pci_bus;
791e2684c0bSAndreas Färber     CPUPPCState *env = NULL;
7923812c71fSAlexander Graf     uint64_t loadaddr;
7933812c71fSAlexander Graf     hwaddr kernel_base = -1LL;
7943812c71fSAlexander Graf     int kernel_size = 0;
7953812c71fSAlexander Graf     hwaddr dt_base = 0;
7963812c71fSAlexander Graf     hwaddr initrd_base = 0;
7973812c71fSAlexander Graf     int initrd_size = 0;
7983812c71fSAlexander Graf     hwaddr cur_base = 0;
7993812c71fSAlexander Graf     char *filename;
8003812c71fSAlexander Graf     hwaddr bios_entry = 0;
8013812c71fSAlexander Graf     target_long bios_size;
8023812c71fSAlexander Graf     struct boot_info *boot_info;
8033812c71fSAlexander Graf     int dt_size;
80482fc73b6SScott Wood     int i;
805d575a6ceSBharat Bhushan     /* irq num for pin INTA, INTB, INTC and INTD is 1, 2, 3 and
806d575a6ceSBharat Bhushan      * 4 respectively */
807d575a6ceSBharat Bhushan     unsigned int pci_irq_nrs[PCI_NUM_PINS] = {1, 2, 3, 4};
808a915249fSAlexander Graf     qemu_irq **irqs, *mpic;
809be13cc7aSAlexander Graf     DeviceState *dev;
810e2684c0bSAndreas Färber     CPUPPCState *firstenv = NULL;
8113eddc1beSBharat Bhushan     MemoryRegion *ccsr_addr_space;
812dffb1dc2SBharat Bhushan     SysBusDevice *s;
8133eddc1beSBharat Bhushan     PPCE500CCSRState *ccsr;
8141db09b84Saurel32 
815e61c36d5SAlexander Graf     /* Setup CPUs */
8163ef96221SMarcel Apfelbaum     if (machine->cpu_model == NULL) {
8173ef96221SMarcel Apfelbaum         machine->cpu_model = "e500v2_v30";
818ef250db6SAlexander Graf     }
819ef250db6SAlexander Graf 
820a915249fSAlexander Graf     irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *));
821a915249fSAlexander Graf     irqs[0] = g_malloc0(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
822e61c36d5SAlexander Graf     for (i = 0; i < smp_cpus; i++) {
823397b457dSAndreas Färber         PowerPCCPU *cpu;
82455e5c285SAndreas Färber         CPUState *cs;
825e61c36d5SAlexander Graf         qemu_irq *input;
826397b457dSAndreas Färber 
8273ef96221SMarcel Apfelbaum         cpu = cpu_ppc_init(machine->cpu_model);
828397b457dSAndreas Färber         if (cpu == NULL) {
8291db09b84Saurel32             fprintf(stderr, "Unable to initialize CPU!\n");
8301db09b84Saurel32             exit(1);
8311db09b84Saurel32         }
832397b457dSAndreas Färber         env = &cpu->env;
83355e5c285SAndreas Färber         cs = CPU(cpu);
8341db09b84Saurel32 
835e61c36d5SAlexander Graf         if (!firstenv) {
836e61c36d5SAlexander Graf             firstenv = env;
837e61c36d5SAlexander Graf         }
838e61c36d5SAlexander Graf 
839a915249fSAlexander Graf         irqs[i] = irqs[0] + (i * OPENPIC_OUTPUT_NB);
840a915249fSAlexander Graf         input = (qemu_irq *)env->irq_inputs;
841a915249fSAlexander Graf         irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT];
842a915249fSAlexander Graf         irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT];
8436a450df9SAlexander Graf         env->spr_cb[SPR_BOOKE_PIR].default_value = cs->cpu_index = i;
84468c2dd70SAlexander Graf         env->mpic_iack = MPC8544_CCSRBAR_BASE +
845bd25922eSScott Wood                          MPC8544_MPIC_REGS_OFFSET + 0xa0;
846e61c36d5SAlexander Graf 
847a34a92b9SAndreas Färber         ppc_booke_timers_init(cpu, 400000000, PPC_TIMER_E500);
8483b989d49SAlexander Graf 
8493b989d49SAlexander Graf         /* Register reset handler */
8505c145dacSAlexander Graf         if (!i) {
8515c145dacSAlexander Graf             /* Primary CPU */
8525c145dacSAlexander Graf             struct boot_info *boot_info;
853e61c36d5SAlexander Graf             boot_info = g_malloc0(sizeof(struct boot_info));
854b3305981SScott Wood             qemu_register_reset(ppce500_cpu_reset, cpu);
855e61c36d5SAlexander Graf             env->load_info = boot_info;
8565c145dacSAlexander Graf         } else {
8575c145dacSAlexander Graf             /* Secondary CPUs */
858b3305981SScott Wood             qemu_register_reset(ppce500_cpu_reset_sec, cpu);
8595c145dacSAlexander Graf         }
860e61c36d5SAlexander Graf     }
861e61c36d5SAlexander Graf 
862e61c36d5SAlexander Graf     env = firstenv;
8633b989d49SAlexander Graf 
8641db09b84Saurel32     /* Fixup Memory size on a alignment boundary */
8651db09b84Saurel32     ram_size &= ~(RAM_SIZES_ALIGN - 1);
8663ef96221SMarcel Apfelbaum     machine->ram_size = ram_size;
8671db09b84Saurel32 
8681db09b84Saurel32     /* Register Memory */
869e938ba0cSShreyas B. Prabhu     memory_region_allocate_system_memory(ram, NULL, "mpc8544ds.ram", ram_size);
8702646c133SAvi Kivity     memory_region_add_subregion(address_space_mem, 0, ram);
8711db09b84Saurel32 
8723eddc1beSBharat Bhushan     dev = qdev_create(NULL, "e500-ccsr");
8733eddc1beSBharat Bhushan     object_property_add_child(qdev_get_machine(), "e500-ccsr",
8743eddc1beSBharat Bhushan                               OBJECT(dev), NULL);
8753eddc1beSBharat Bhushan     qdev_init_nofail(dev);
8763eddc1beSBharat Bhushan     ccsr = CCSR(dev);
8773eddc1beSBharat Bhushan     ccsr_addr_space = &ccsr->ccsr_space;
8783eddc1beSBharat Bhushan     memory_region_add_subregion(address_space_mem, MPC8544_CCSRBAR_BASE,
8793eddc1beSBharat Bhushan                                 ccsr_addr_space);
880dffb1dc2SBharat Bhushan 
88182fc73b6SScott Wood     mpic = ppce500_init_mpic(params, ccsr_addr_space, irqs);
8821db09b84Saurel32 
8831db09b84Saurel32     /* Serial */
8842d48377aSBlue Swirl     if (serial_hds[0]) {
8853eddc1beSBharat Bhushan         serial_mm_init(ccsr_addr_space, MPC8544_SERIAL0_REGS_OFFSET,
886cdbb912aSAlexander Graf                        0, mpic[42], 399193,
8872ff0c7c3SRichard Henderson                        serial_hds[0], DEVICE_BIG_ENDIAN);
8882d48377aSBlue Swirl     }
8891db09b84Saurel32 
8902d48377aSBlue Swirl     if (serial_hds[1]) {
8913eddc1beSBharat Bhushan         serial_mm_init(ccsr_addr_space, MPC8544_SERIAL1_REGS_OFFSET,
892cdbb912aSAlexander Graf                        0, mpic[42], 399193,
89359de4f98SBharat Bhushan                        serial_hds[1], DEVICE_BIG_ENDIAN);
8942d48377aSBlue Swirl     }
8951db09b84Saurel32 
896b0fb8423SAlexander Graf     /* General Utility device */
897dffb1dc2SBharat Bhushan     dev = qdev_create(NULL, "mpc8544-guts");
898dffb1dc2SBharat Bhushan     qdev_init_nofail(dev);
899dffb1dc2SBharat Bhushan     s = SYS_BUS_DEVICE(dev);
9003eddc1beSBharat Bhushan     memory_region_add_subregion(ccsr_addr_space, MPC8544_UTIL_OFFSET,
901dffb1dc2SBharat Bhushan                                 sysbus_mmio_get_region(s, 0));
902b0fb8423SAlexander Graf 
9031db09b84Saurel32     /* PCI */
904dffb1dc2SBharat Bhushan     dev = qdev_create(NULL, "e500-pcihost");
905492ec48dSAlexander Graf     qdev_prop_set_uint32(dev, "first_slot", params->pci_first_slot);
9063016dca0SBharat Bhushan     qdev_prop_set_uint32(dev, "first_pin_irq", pci_irq_nrs[0]);
907dffb1dc2SBharat Bhushan     qdev_init_nofail(dev);
908dffb1dc2SBharat Bhushan     s = SYS_BUS_DEVICE(dev);
909d575a6ceSBharat Bhushan     for (i = 0; i < PCI_NUM_PINS; i++) {
910d575a6ceSBharat Bhushan         sysbus_connect_irq(s, i, mpic[pci_irq_nrs[i]]);
911d575a6ceSBharat Bhushan     }
912d575a6ceSBharat Bhushan 
9133eddc1beSBharat Bhushan     memory_region_add_subregion(ccsr_addr_space, MPC8544_PCI_REGS_OFFSET,
914dffb1dc2SBharat Bhushan                                 sysbus_mmio_get_region(s, 0));
915dffb1dc2SBharat Bhushan 
916d461e3b9SAlexander Graf     pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
9171db09b84Saurel32     if (!pci_bus)
9181db09b84Saurel32         printf("couldn't create PCI controller!\n");
9191db09b84Saurel32 
9201356b98dSAndreas Färber     sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, MPC8544_PCI_IO);
9211db09b84Saurel32 
9221db09b84Saurel32     if (pci_bus) {
9231db09b84Saurel32         /* Register network interfaces. */
9241db09b84Saurel32         for (i = 0; i < nb_nics; i++) {
92529b358f9SDavid Gibson             pci_nic_init_nofail(&nd_table[i], pci_bus, "virtio", NULL);
9261db09b84Saurel32         }
9271db09b84Saurel32     }
9281db09b84Saurel32 
9295c145dacSAlexander Graf     /* Register spinning region */
9305c145dacSAlexander Graf     sysbus_create_simple("e500-spin", MPC8544_SPIN_BASE, NULL);
9315c145dacSAlexander Graf 
9323812c71fSAlexander Graf     if (cur_base < (32 * 1024 * 1024)) {
9333812c71fSAlexander Graf         /* u-boot occupies memory up to 32MB, so load blobs above */
9343812c71fSAlexander Graf         cur_base = (32 * 1024 * 1024);
9353812c71fSAlexander Graf     }
9363812c71fSAlexander Graf 
937b88e77f4SAlexander Graf     if (params->has_mpc8xxx_gpio) {
938016f7758SAlexander Graf         qemu_irq poweroff_irq;
939016f7758SAlexander Graf 
940b88e77f4SAlexander Graf         dev = qdev_create(NULL, "mpc8xxx_gpio");
941b88e77f4SAlexander Graf         s = SYS_BUS_DEVICE(dev);
942b88e77f4SAlexander Graf         qdev_init_nofail(dev);
943b88e77f4SAlexander Graf         sysbus_connect_irq(s, 0, mpic[MPC8XXX_GPIO_IRQ]);
944b88e77f4SAlexander Graf         memory_region_add_subregion(ccsr_addr_space, MPC8XXX_GPIO_OFFSET,
945b88e77f4SAlexander Graf                                     sysbus_mmio_get_region(s, 0));
946016f7758SAlexander Graf 
947016f7758SAlexander Graf         /* Power Off GPIO at Pin 0 */
948016f7758SAlexander Graf         poweroff_irq = qemu_allocate_irq(ppce500_power_off, NULL, 0);
949016f7758SAlexander Graf         qdev_connect_gpio_out(dev, 0, poweroff_irq);
950b88e77f4SAlexander Graf     }
951b88e77f4SAlexander Graf 
952f7087343SAlexander Graf     /* Platform Bus Device */
953f7087343SAlexander Graf     if (params->has_platform_bus) {
954f7087343SAlexander Graf         dev = qdev_create(NULL, TYPE_PLATFORM_BUS_DEVICE);
955f7087343SAlexander Graf         dev->id = TYPE_PLATFORM_BUS_DEVICE;
956f7087343SAlexander Graf         qdev_prop_set_uint32(dev, "num_irqs", params->platform_bus_num_irqs);
957f7087343SAlexander Graf         qdev_prop_set_uint32(dev, "mmio_size", params->platform_bus_size);
958f7087343SAlexander Graf         qdev_init_nofail(dev);
959f7087343SAlexander Graf         s = SYS_BUS_DEVICE(dev);
960f7087343SAlexander Graf 
961f7087343SAlexander Graf         for (i = 0; i < params->platform_bus_num_irqs; i++) {
962f7087343SAlexander Graf             int irqn = params->platform_bus_first_irq + i;
963f7087343SAlexander Graf             sysbus_connect_irq(s, i, mpic[irqn]);
964f7087343SAlexander Graf         }
965f7087343SAlexander Graf 
966f7087343SAlexander Graf         memory_region_add_subregion(address_space_mem,
967f7087343SAlexander Graf                                     params->platform_bus_base,
968f7087343SAlexander Graf                                     sysbus_mmio_get_region(s, 0));
969f7087343SAlexander Graf     }
970f7087343SAlexander Graf 
9711db09b84Saurel32     /* Load kernel. */
9723ef96221SMarcel Apfelbaum     if (machine->kernel_filename) {
9733812c71fSAlexander Graf         kernel_base = cur_base;
9743812c71fSAlexander Graf         kernel_size = load_image_targphys(machine->kernel_filename,
9753812c71fSAlexander Graf                                           cur_base,
9763812c71fSAlexander Graf                                           ram_size - cur_base);
9771db09b84Saurel32         if (kernel_size < 0) {
9781db09b84Saurel32             fprintf(stderr, "qemu: could not load kernel '%s'\n",
9793ef96221SMarcel Apfelbaum                     machine->kernel_filename);
9801db09b84Saurel32             exit(1);
9811db09b84Saurel32         }
982528e536eSAlexander Graf 
9833812c71fSAlexander Graf         cur_base += kernel_size;
9841db09b84Saurel32     }
9851db09b84Saurel32 
9861db09b84Saurel32     /* Load initrd. */
9873ef96221SMarcel Apfelbaum     if (machine->initrd_filename) {
988528e536eSAlexander Graf         initrd_base = (cur_base + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK;
9893ef96221SMarcel Apfelbaum         initrd_size = load_image_targphys(machine->initrd_filename, initrd_base,
990d7585251Spbrook                                           ram_size - initrd_base);
9911db09b84Saurel32 
9921db09b84Saurel32         if (initrd_size < 0) {
9931db09b84Saurel32             fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
9943ef96221SMarcel Apfelbaum                     machine->initrd_filename);
9951db09b84Saurel32             exit(1);
9961db09b84Saurel32         }
997528e536eSAlexander Graf 
998528e536eSAlexander Graf         cur_base = initrd_base + initrd_size;
9991db09b84Saurel32     }
10001db09b84Saurel32 
10013812c71fSAlexander Graf     /*
10023812c71fSAlexander Graf      * Smart firmware defaults ahead!
10033812c71fSAlexander Graf      *
10043812c71fSAlexander Graf      * We follow the following table to select which payload we execute.
10053812c71fSAlexander Graf      *
10063812c71fSAlexander Graf      *  -kernel | -bios | payload
10073812c71fSAlexander Graf      * ---------+-------+---------
10083812c71fSAlexander Graf      *     N    |   Y   | u-boot
10093812c71fSAlexander Graf      *     N    |   N   | u-boot
10103812c71fSAlexander Graf      *     Y    |   Y   | u-boot
10113812c71fSAlexander Graf      *     Y    |   N   | kernel
10123812c71fSAlexander Graf      *
10133812c71fSAlexander Graf      * This ensures backwards compatibility with how we used to expose
10143812c71fSAlexander Graf      * -kernel to users but allows them to run through u-boot as well.
10153812c71fSAlexander Graf      */
10163812c71fSAlexander Graf     if (bios_name == NULL) {
10173ef96221SMarcel Apfelbaum         if (machine->kernel_filename) {
10183812c71fSAlexander Graf             bios_name = machine->kernel_filename;
10193812c71fSAlexander Graf         } else {
10203812c71fSAlexander Graf             bios_name = "u-boot.e500";
10213812c71fSAlexander Graf         }
10223812c71fSAlexander Graf     }
10233812c71fSAlexander Graf     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
10243812c71fSAlexander Graf 
10253812c71fSAlexander Graf     bios_size = load_elf(filename, NULL, NULL, &bios_entry, &loadaddr, NULL,
10263812c71fSAlexander Graf                          1, ELF_MACHINE, 0);
10273812c71fSAlexander Graf     if (bios_size < 0) {
10283812c71fSAlexander Graf         /*
10293812c71fSAlexander Graf          * Hrm. No ELF image? Try a uImage, maybe someone is giving us an
10303812c71fSAlexander Graf          * ePAPR compliant kernel
10313812c71fSAlexander Graf          */
103225bda50aSMax Filippov         kernel_size = load_uimage(filename, &bios_entry, &loadaddr, NULL,
103325bda50aSMax Filippov                                   NULL, NULL);
10343812c71fSAlexander Graf         if (kernel_size < 0) {
10353812c71fSAlexander Graf             fprintf(stderr, "qemu: could not load firmware '%s'\n", filename);
10363812c71fSAlexander Graf             exit(1);
10373812c71fSAlexander Graf         }
10383812c71fSAlexander Graf     }
10393812c71fSAlexander Graf 
10403812c71fSAlexander Graf     /* Reserve space for dtb */
10413812c71fSAlexander Graf     dt_base = (loadaddr + bios_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
10425c145dacSAlexander Graf 
10433ef96221SMarcel Apfelbaum     dt_size = ppce500_prep_device_tree(machine, params, dt_base,
1044903585deSAlexander Graf                                        initrd_base, initrd_size,
10453812c71fSAlexander Graf                                        kernel_base, kernel_size);
1046cba2026aSAlexander Graf     if (dt_size < 0) {
10471db09b84Saurel32         fprintf(stderr, "couldn't load device tree\n");
10481db09b84Saurel32         exit(1);
10491db09b84Saurel32     }
1050b8dec144SAlexander Graf     assert(dt_size < DTB_MAX_SIZE);
10511db09b84Saurel32 
1052e61c36d5SAlexander Graf     boot_info = env->load_info;
10533812c71fSAlexander Graf     boot_info->entry = bios_entry;
10543b989d49SAlexander Graf     boot_info->dt_base = dt_base;
1055cba2026aSAlexander Graf     boot_info->dt_size = dt_size;
10561db09b84Saurel32 
10573b989d49SAlexander Graf     if (kvm_enabled()) {
10581db09b84Saurel32         kvmppc_init();
10593b989d49SAlexander Graf     }
10601db09b84Saurel32 }
10613eddc1beSBharat Bhushan 
10623eddc1beSBharat Bhushan static int e500_ccsr_initfn(SysBusDevice *dev)
10633eddc1beSBharat Bhushan {
10643eddc1beSBharat Bhushan     PPCE500CCSRState *ccsr;
10653eddc1beSBharat Bhushan 
10663eddc1beSBharat Bhushan     ccsr = CCSR(dev);
106740c5dce9SPaolo Bonzini     memory_region_init(&ccsr->ccsr_space, OBJECT(ccsr), "e500-ccsr",
10683eddc1beSBharat Bhushan                        MPC8544_CCSRBAR_SIZE);
10693eddc1beSBharat Bhushan     return 0;
10703eddc1beSBharat Bhushan }
10713eddc1beSBharat Bhushan 
10723eddc1beSBharat Bhushan static void e500_ccsr_class_init(ObjectClass *klass, void *data)
10733eddc1beSBharat Bhushan {
10743eddc1beSBharat Bhushan     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
10753eddc1beSBharat Bhushan     k->init = e500_ccsr_initfn;
10763eddc1beSBharat Bhushan }
10773eddc1beSBharat Bhushan 
10783eddc1beSBharat Bhushan static const TypeInfo e500_ccsr_info = {
10793eddc1beSBharat Bhushan     .name          = TYPE_CCSR,
10803eddc1beSBharat Bhushan     .parent        = TYPE_SYS_BUS_DEVICE,
10813eddc1beSBharat Bhushan     .instance_size = sizeof(PPCE500CCSRState),
10823eddc1beSBharat Bhushan     .class_init    = e500_ccsr_class_init,
10833eddc1beSBharat Bhushan };
10843eddc1beSBharat Bhushan 
10853eddc1beSBharat Bhushan static void e500_register_types(void)
10863eddc1beSBharat Bhushan {
10873eddc1beSBharat Bhushan     type_register_static(&e500_ccsr_info);
10883eddc1beSBharat Bhushan }
10893eddc1beSBharat Bhushan 
10903eddc1beSBharat Bhushan type_init(e500_register_types)
1091