xref: /qemu/hw/ppc/e500.c (revision aa2ac1dac3d27b412e2dba4cde38724446751344)
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"
391db09b84Saurel32 
40cefd3cdbSBharat Bhushan #define EPAPR_MAGIC                (0x45504150)
411db09b84Saurel32 #define BINARY_DEVICE_TREE_FILE    "mpc8544ds.dtb"
429dd5eba1SScott Wood #define DTC_LOAD_PAD               0x1800000
4375bb6589SLiu Yu #define DTC_PAD_MASK               0xFFFFF
44b8dec144SAlexander Graf #define DTB_MAX_SIZE               (8 * 1024 * 1024)
4575bb6589SLiu Yu #define INITRD_LOAD_PAD            0x2000000
4675bb6589SLiu Yu #define INITRD_PAD_MASK            0xFFFFFF
471db09b84Saurel32 
481db09b84Saurel32 #define RAM_SIZES_ALIGN            (64UL << 20)
491db09b84Saurel32 
50b3305981SScott Wood /* TODO: parameterize */
51ed2bc496SAlexander Graf #define MPC8544_CCSRBAR_BASE       0xE0000000ULL
52ed2bc496SAlexander Graf #define MPC8544_CCSRBAR_SIZE       0x00100000ULL
53dffb1dc2SBharat Bhushan #define MPC8544_MPIC_REGS_OFFSET   0x40000ULL
54a911b7a9SAlexander Graf #define MPC8544_MSI_REGS_OFFSET   0x41600ULL
55dffb1dc2SBharat Bhushan #define MPC8544_SERIAL0_REGS_OFFSET 0x4500ULL
56dffb1dc2SBharat Bhushan #define MPC8544_SERIAL1_REGS_OFFSET 0x4600ULL
57dffb1dc2SBharat Bhushan #define MPC8544_PCI_REGS_OFFSET    0x8000ULL
58dffb1dc2SBharat Bhushan #define MPC8544_PCI_REGS_BASE      (MPC8544_CCSRBAR_BASE + \
59dffb1dc2SBharat Bhushan                                     MPC8544_PCI_REGS_OFFSET)
60ed2bc496SAlexander Graf #define MPC8544_PCI_REGS_SIZE      0x1000ULL
61ed2bc496SAlexander Graf #define MPC8544_PCI_IO             0xE1000000ULL
62dffb1dc2SBharat Bhushan #define MPC8544_UTIL_OFFSET        0xe0000ULL
63ed2bc496SAlexander Graf #define MPC8544_SPIN_BASE          0xEF000000ULL
641db09b84Saurel32 
653b989d49SAlexander Graf struct boot_info
663b989d49SAlexander Graf {
673b989d49SAlexander Graf     uint32_t dt_base;
68cba2026aSAlexander Graf     uint32_t dt_size;
693b989d49SAlexander Graf     uint32_t entry;
703b989d49SAlexander Graf };
713b989d49SAlexander Graf 
72347dd79dSAlexander Graf static uint32_t *pci_map_create(void *fdt, uint32_t mpic, int first_slot,
73347dd79dSAlexander Graf                                 int nr_slots, int *len)
740dbc0798SAlexander Graf {
75347dd79dSAlexander Graf     int i = 0;
76347dd79dSAlexander Graf     int slot;
77347dd79dSAlexander Graf     int pci_irq;
789e2c1298SAlexander Graf     int host_irq;
79347dd79dSAlexander Graf     int last_slot = first_slot + nr_slots;
80347dd79dSAlexander Graf     uint32_t *pci_map;
810dbc0798SAlexander Graf 
82347dd79dSAlexander Graf     *len = nr_slots * 4 * 7 * sizeof(uint32_t);
83347dd79dSAlexander Graf     pci_map = g_malloc(*len);
84347dd79dSAlexander Graf 
85347dd79dSAlexander Graf     for (slot = first_slot; slot < last_slot; slot++) {
86347dd79dSAlexander Graf         for (pci_irq = 0; pci_irq < 4; pci_irq++) {
87347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(slot << 11);
88347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(0x0);
89347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(0x0);
90347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(pci_irq + 1);
91347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(mpic);
929e2c1298SAlexander Graf             host_irq = ppce500_pci_map_irq_slot(slot, pci_irq);
939e2c1298SAlexander Graf             pci_map[i++] = cpu_to_be32(host_irq + 1);
94347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(0x1);
950dbc0798SAlexander Graf         }
960dbc0798SAlexander Graf     }
970dbc0798SAlexander Graf 
98347dd79dSAlexander Graf     assert((i * sizeof(uint32_t)) == *len);
99347dd79dSAlexander Graf 
100347dd79dSAlexander Graf     return pci_map;
101347dd79dSAlexander Graf }
102347dd79dSAlexander Graf 
103a053a7ceSAlexander Graf static void dt_serial_create(void *fdt, unsigned long long offset,
104a053a7ceSAlexander Graf                              const char *soc, const char *mpic,
105a053a7ceSAlexander Graf                              const char *alias, int idx, bool defcon)
106a053a7ceSAlexander Graf {
107a053a7ceSAlexander Graf     char ser[128];
108a053a7ceSAlexander Graf 
109a053a7ceSAlexander Graf     snprintf(ser, sizeof(ser), "%s/serial@%llx", soc, offset);
1105a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, ser);
1115a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, ser, "device_type", "serial");
1125a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, ser, "compatible", "ns16550");
1135a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, ser, "reg", offset, 0x100);
1145a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, ser, "cell-index", idx);
1155a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, ser, "clock-frequency", 0);
1165a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, ser, "interrupts", 42, 2);
1175a4348d1SPeter Crosthwaite     qemu_fdt_setprop_phandle(fdt, ser, "interrupt-parent", mpic);
1185a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, "/aliases", alias, ser);
119a053a7ceSAlexander Graf 
120a053a7ceSAlexander Graf     if (defcon) {
1215a4348d1SPeter Crosthwaite         qemu_fdt_setprop_string(fdt, "/chosen", "linux,stdout-path", ser);
122a053a7ceSAlexander Graf     }
123a053a7ceSAlexander Graf }
124a053a7ceSAlexander Graf 
1253ef96221SMarcel Apfelbaum static int ppce500_load_device_tree(MachineState *machine,
126e6eaabebSScott Wood                                     PPCE500Params *params,
127a8170e5eSAvi Kivity                                     hwaddr addr,
128a8170e5eSAvi Kivity                                     hwaddr initrd_base,
12928290f37SAlexander Graf                                     hwaddr initrd_size,
130903585deSAlexander Graf                                     hwaddr kernel_base,
131903585deSAlexander Graf                                     hwaddr kernel_size,
13228290f37SAlexander Graf                                     bool dry_run)
1331db09b84Saurel32 {
13428290f37SAlexander Graf     CPUPPCState *env = first_cpu->env_ptr;
135dbf916d8SAurelien Jarno     int ret = -1;
1363ef96221SMarcel Apfelbaum     uint64_t mem_reg_property[] = { 0, cpu_to_be64(machine->ram_size) };
1377ec632b4Spbrook     int fdt_size;
138dbf916d8SAurelien Jarno     void *fdt;
1395de6b46dSAlexander Graf     uint8_t hypercall[16];
140911d6e7aSAlexander Graf     uint32_t clock_freq = 400000000;
141911d6e7aSAlexander Graf     uint32_t tb_freq = 400000000;
142621d05e3SAlexander Graf     int i;
143ebb9518aSAlexander Graf     char compatible_sb[] = "fsl,mpc8544-immr\0simple-bus";
1445da96624SAlexander Graf     char soc[128];
14519ac9deaSAlexander Graf     char mpic[128];
14619ac9deaSAlexander Graf     uint32_t mpic_ph;
147a911b7a9SAlexander Graf     uint32_t msi_ph;
148f5038483SAlexander Graf     char gutil[128];
1490dbc0798SAlexander Graf     char pci[128];
150a911b7a9SAlexander Graf     char msi[128];
151347dd79dSAlexander Graf     uint32_t *pci_map = NULL;
152347dd79dSAlexander Graf     int len;
1533627757eSAlexander Graf     uint32_t pci_ranges[14] =
1543627757eSAlexander Graf         {
1553627757eSAlexander Graf             0x2000000, 0x0, 0xc0000000,
1563627757eSAlexander Graf             0x0, 0xc0000000,
1573627757eSAlexander Graf             0x0, 0x20000000,
1583627757eSAlexander Graf 
1593627757eSAlexander Graf             0x1000000, 0x0, 0x0,
1603627757eSAlexander Graf             0x0, 0xe1000000,
1613627757eSAlexander Graf             0x0, 0x10000,
1623627757eSAlexander Graf         };
1632ff3de68SMarkus Armbruster     QemuOpts *machine_opts = qemu_get_machine_opts();
1642ff3de68SMarkus Armbruster     const char *dtb_file = qemu_opt_get(machine_opts, "dtb");
1652ff3de68SMarkus Armbruster     const char *toplevel_compat = qemu_opt_get(machine_opts, "dt_compatible");
166d1b93565SAlexander Graf 
167d1b93565SAlexander Graf     if (dtb_file) {
168d1b93565SAlexander Graf         char *filename;
169d1b93565SAlexander Graf         filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_file);
170d1b93565SAlexander Graf         if (!filename) {
171d1b93565SAlexander Graf             goto out;
172d1b93565SAlexander Graf         }
173d1b93565SAlexander Graf 
174d1b93565SAlexander Graf         fdt = load_device_tree(filename, &fdt_size);
175d1b93565SAlexander Graf         if (!fdt) {
176d1b93565SAlexander Graf             goto out;
177d1b93565SAlexander Graf         }
178d1b93565SAlexander Graf         goto done;
179d1b93565SAlexander Graf     }
1801db09b84Saurel32 
1812636fcb6SAlexander Graf     fdt = create_device_tree(&fdt_size);
1825cea8590SPaul Brook     if (fdt == NULL) {
1835cea8590SPaul Brook         goto out;
1845cea8590SPaul Brook     }
1851db09b84Saurel32 
1861db09b84Saurel32     /* Manipulate device tree in memory. */
1875a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 2);
1885a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 2);
18951b852b7SAlexander Graf 
1905a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, "/memory");
1915a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, "/memory", "device_type", "memory");
1925a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, "/memory", "reg", mem_reg_property,
1931db09b84Saurel32                      sizeof(mem_reg_property));
1941db09b84Saurel32 
1955a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, "/chosen");
1963b989d49SAlexander Graf     if (initrd_size) {
1975a4348d1SPeter Crosthwaite         ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start",
1981db09b84Saurel32                                     initrd_base);
1993b989d49SAlexander Graf         if (ret < 0) {
2001db09b84Saurel32             fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
2013b989d49SAlexander Graf         }
2021db09b84Saurel32 
2035a4348d1SPeter Crosthwaite         ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
2041db09b84Saurel32                                     (initrd_base + initrd_size));
2053b989d49SAlexander Graf         if (ret < 0) {
2061db09b84Saurel32             fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
2073b989d49SAlexander Graf         }
208903585deSAlexander Graf 
209903585deSAlexander Graf     }
210903585deSAlexander Graf 
211903585deSAlexander Graf     if (kernel_base != -1ULL) {
212903585deSAlexander Graf         qemu_fdt_setprop_cells(fdt, "/chosen", "qemu,boot-kernel",
213903585deSAlexander Graf                                      kernel_base >> 32, kernel_base,
214903585deSAlexander Graf                                      kernel_size >> 32, kernel_size);
2153b989d49SAlexander Graf     }
2161db09b84Saurel32 
2175a4348d1SPeter Crosthwaite     ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
2183ef96221SMarcel Apfelbaum                                       machine->kernel_cmdline);
2191db09b84Saurel32     if (ret < 0)
2201db09b84Saurel32         fprintf(stderr, "couldn't set /chosen/bootargs\n");
2211db09b84Saurel32 
2221db09b84Saurel32     if (kvm_enabled()) {
223911d6e7aSAlexander Graf         /* Read out host's frequencies */
224911d6e7aSAlexander Graf         clock_freq = kvmppc_get_clockfreq();
225911d6e7aSAlexander Graf         tb_freq = kvmppc_get_tbfreq();
2265de6b46dSAlexander Graf 
2275de6b46dSAlexander Graf         /* indicate KVM hypercall interface */
2285a4348d1SPeter Crosthwaite         qemu_fdt_add_subnode(fdt, "/hypervisor");
2295a4348d1SPeter Crosthwaite         qemu_fdt_setprop_string(fdt, "/hypervisor", "compatible",
2305de6b46dSAlexander Graf                                 "linux,kvm");
2315de6b46dSAlexander Graf         kvmppc_get_hypercall(env, hypercall, sizeof(hypercall));
2325a4348d1SPeter Crosthwaite         qemu_fdt_setprop(fdt, "/hypervisor", "hcall-instructions",
2335de6b46dSAlexander Graf                          hypercall, sizeof(hypercall));
2341a61a9aeSStuart Yoder         /* if KVM supports the idle hcall, set property indicating this */
2351a61a9aeSStuart Yoder         if (kvmppc_get_hasidle(env)) {
2365a4348d1SPeter Crosthwaite             qemu_fdt_setprop(fdt, "/hypervisor", "has-idle", NULL, 0);
2371a61a9aeSStuart Yoder         }
2381db09b84Saurel32     }
2391db09b84Saurel32 
240625e665bSAlexander Graf     /* Create CPU nodes */
2415a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, "/cpus");
2425a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 1);
2435a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0);
244625e665bSAlexander Graf 
2451e3debf0SAlexander Graf     /* We need to generate the cpu nodes in reverse order, so Linux can pick
2461e3debf0SAlexander Graf        the first node as boot node and be happy */
2471e3debf0SAlexander Graf     for (i = smp_cpus - 1; i >= 0; i--) {
248440c8152SAndreas Färber         CPUState *cpu;
2490f20ba62SAlexey Kardashevskiy         PowerPCCPU *pcpu;
250621d05e3SAlexander Graf         char cpu_name[128];
2511d2e5c52SAlexander Graf         uint64_t cpu_release_addr = MPC8544_SPIN_BASE + (i * 0x20);
25210f25a46SAlexander Graf 
253440c8152SAndreas Färber         cpu = qemu_get_cpu(i);
25455e5c285SAndreas Färber         if (cpu == NULL) {
2551e3debf0SAlexander Graf             continue;
2561e3debf0SAlexander Graf         }
257440c8152SAndreas Färber         env = cpu->env_ptr;
2580f20ba62SAlexey Kardashevskiy         pcpu = POWERPC_CPU(cpu);
2591e3debf0SAlexander Graf 
26055e5c285SAndreas Färber         snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x",
2610f20ba62SAlexey Kardashevskiy                  ppc_get_vcpu_dt_id(pcpu));
2625a4348d1SPeter Crosthwaite         qemu_fdt_add_subnode(fdt, cpu_name);
2635a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq);
2645a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq);
2655a4348d1SPeter Crosthwaite         qemu_fdt_setprop_string(fdt, cpu_name, "device_type", "cpu");
2660f20ba62SAlexey Kardashevskiy         qemu_fdt_setprop_cell(fdt, cpu_name, "reg",
2670f20ba62SAlexey Kardashevskiy                               ppc_get_vcpu_dt_id(pcpu));
2685a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-line-size",
2691e3debf0SAlexander Graf                               env->dcache_line_size);
2705a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-line-size",
2711e3debf0SAlexander Graf                               env->icache_line_size);
2725a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-size", 0x8000);
2735a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-size", 0x8000);
2745a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "bus-frequency", 0);
27555e5c285SAndreas Färber         if (cpu->cpu_index) {
2765a4348d1SPeter Crosthwaite             qemu_fdt_setprop_string(fdt, cpu_name, "status", "disabled");
2775a4348d1SPeter Crosthwaite             qemu_fdt_setprop_string(fdt, cpu_name, "enable-method",
2785a4348d1SPeter Crosthwaite                                     "spin-table");
2795a4348d1SPeter Crosthwaite             qemu_fdt_setprop_u64(fdt, cpu_name, "cpu-release-addr",
2801d2e5c52SAlexander Graf                                  cpu_release_addr);
2811e3debf0SAlexander Graf         } else {
2825a4348d1SPeter Crosthwaite             qemu_fdt_setprop_string(fdt, cpu_name, "status", "okay");
2831e3debf0SAlexander Graf         }
2841db09b84Saurel32     }
2851db09b84Saurel32 
2865a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, "/aliases");
2875da96624SAlexander Graf     /* XXX These should go into their respective devices' code */
288ed2bc496SAlexander Graf     snprintf(soc, sizeof(soc), "/soc@%llx", MPC8544_CCSRBAR_BASE);
2895a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, soc);
2905a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, soc, "device_type", "soc");
2915a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, soc, "compatible", compatible_sb,
292ebb9518aSAlexander Graf                      sizeof(compatible_sb));
2935a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, soc, "#address-cells", 1);
2945a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, soc, "#size-cells", 1);
2955a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, soc, "ranges", 0x0,
2963627757eSAlexander Graf                            MPC8544_CCSRBAR_BASE >> 32, MPC8544_CCSRBAR_BASE,
2975da96624SAlexander Graf                            MPC8544_CCSRBAR_SIZE);
2985da96624SAlexander Graf     /* XXX should contain a reasonable value */
2995a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, soc, "bus-frequency", 0);
3005da96624SAlexander Graf 
301dffb1dc2SBharat Bhushan     snprintf(mpic, sizeof(mpic), "%s/pic@%llx", soc, MPC8544_MPIC_REGS_OFFSET);
3025a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, mpic);
3035a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, mpic, "device_type", "open-pic");
3045a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, mpic, "compatible", "fsl,mpic");
3055a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_OFFSET,
306dffb1dc2SBharat Bhushan                            0x40000);
3075a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, mpic, "#address-cells", 0);
3085a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, mpic, "#interrupt-cells", 2);
3095a4348d1SPeter Crosthwaite     mpic_ph = qemu_fdt_alloc_phandle(fdt);
3105a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, mpic, "phandle", mpic_ph);
3115a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, mpic, "linux,phandle", mpic_ph);
3125a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, mpic, "interrupt-controller", NULL, 0);
31319ac9deaSAlexander Graf 
3140cfc6e8dSAlexander Graf     /*
3150cfc6e8dSAlexander Graf      * We have to generate ser1 first, because Linux takes the first
3160cfc6e8dSAlexander Graf      * device it finds in the dt as serial output device. And we generate
3170cfc6e8dSAlexander Graf      * devices in reverse order to the dt.
3180cfc6e8dSAlexander Graf      */
31979c0ff2cSAlexander Graf     if (serial_hds[1]) {
320dffb1dc2SBharat Bhushan         dt_serial_create(fdt, MPC8544_SERIAL1_REGS_OFFSET,
321a053a7ceSAlexander Graf                          soc, mpic, "serial1", 1, false);
32279c0ff2cSAlexander Graf     }
32379c0ff2cSAlexander Graf 
32479c0ff2cSAlexander Graf     if (serial_hds[0]) {
325dffb1dc2SBharat Bhushan         dt_serial_create(fdt, MPC8544_SERIAL0_REGS_OFFSET,
326a053a7ceSAlexander Graf                          soc, mpic, "serial0", 0, true);
32779c0ff2cSAlexander Graf     }
3280cfc6e8dSAlexander Graf 
329ed2bc496SAlexander Graf     snprintf(gutil, sizeof(gutil), "%s/global-utilities@%llx", soc,
330dffb1dc2SBharat Bhushan              MPC8544_UTIL_OFFSET);
3315a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, gutil);
3325a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, gutil, "compatible", "fsl,mpc8544-guts");
3335a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, gutil, "reg", MPC8544_UTIL_OFFSET, 0x1000);
3345a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, gutil, "fsl,has-rstcr", NULL, 0);
335f5038483SAlexander Graf 
336a911b7a9SAlexander Graf     snprintf(msi, sizeof(msi), "/%s/msi@%llx", soc, MPC8544_MSI_REGS_OFFSET);
3375a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, msi);
3385a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, msi, "compatible", "fsl,mpic-msi");
3395a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, msi, "reg", MPC8544_MSI_REGS_OFFSET, 0x200);
3405a4348d1SPeter Crosthwaite     msi_ph = qemu_fdt_alloc_phandle(fdt);
3415a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, msi, "msi-available-ranges", 0x0, 0x100);
3425a4348d1SPeter Crosthwaite     qemu_fdt_setprop_phandle(fdt, msi, "interrupt-parent", mpic);
3435a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, msi, "interrupts",
344a911b7a9SAlexander Graf         0xe0, 0x0,
345a911b7a9SAlexander Graf         0xe1, 0x0,
346a911b7a9SAlexander Graf         0xe2, 0x0,
347a911b7a9SAlexander Graf         0xe3, 0x0,
348a911b7a9SAlexander Graf         0xe4, 0x0,
349a911b7a9SAlexander Graf         0xe5, 0x0,
350a911b7a9SAlexander Graf         0xe6, 0x0,
351a911b7a9SAlexander Graf         0xe7, 0x0);
3525a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, msi, "phandle", msi_ph);
3535a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, msi, "linux,phandle", msi_ph);
354a911b7a9SAlexander Graf 
355ed2bc496SAlexander Graf     snprintf(pci, sizeof(pci), "/pci@%llx", MPC8544_PCI_REGS_BASE);
3565a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, pci);
3575a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "cell-index", 0);
3585a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, pci, "compatible", "fsl,mpc8540-pci");
3595a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, pci, "device_type", "pci");
3605a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, pci, "interrupt-map-mask", 0xf800, 0x0,
3610dbc0798SAlexander Graf                            0x0, 0x7);
3625a4348d1SPeter Crosthwaite     pci_map = pci_map_create(fdt, qemu_fdt_get_phandle(fdt, mpic),
363492ec48dSAlexander Graf                              params->pci_first_slot, params->pci_nr_slots,
364492ec48dSAlexander Graf                              &len);
3655a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, pci, "interrupt-map", pci_map, len);
3665a4348d1SPeter Crosthwaite     qemu_fdt_setprop_phandle(fdt, pci, "interrupt-parent", mpic);
3675a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, pci, "interrupts", 24, 2);
3685a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, pci, "bus-range", 0, 255);
3693627757eSAlexander Graf     for (i = 0; i < 14; i++) {
3700dbc0798SAlexander Graf         pci_ranges[i] = cpu_to_be32(pci_ranges[i]);
3710dbc0798SAlexander Graf     }
3725a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "fsl,msi", msi_ph);
3735a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, pci, "ranges", pci_ranges, sizeof(pci_ranges));
3745a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, pci, "reg", MPC8544_PCI_REGS_BASE >> 32,
3753627757eSAlexander Graf                            MPC8544_PCI_REGS_BASE, 0, 0x1000);
3765a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "clock-frequency", 66666666);
3775a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "#interrupt-cells", 1);
3785a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "#size-cells", 2);
3795a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "#address-cells", 3);
3805a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, "/aliases", "pci0", pci);
3810dbc0798SAlexander Graf 
382e6eaabebSScott Wood     params->fixup_devtree(params, fdt);
383e6eaabebSScott Wood 
384e6eaabebSScott Wood     if (toplevel_compat) {
3855a4348d1SPeter Crosthwaite         qemu_fdt_setprop(fdt, "/", "compatible", toplevel_compat,
386e6eaabebSScott Wood                          strlen(toplevel_compat) + 1);
387e6eaabebSScott Wood     }
388e6eaabebSScott Wood 
389d1b93565SAlexander Graf done:
39028290f37SAlexander Graf     if (!dry_run) {
3915a4348d1SPeter Crosthwaite         qemu_fdt_dumpdtb(fdt, fdt_size);
39228290f37SAlexander Graf         cpu_physical_memory_write(addr, fdt, fdt_size);
393cba2026aSAlexander Graf     }
394cba2026aSAlexander Graf     ret = fdt_size;
3957ec632b4Spbrook 
3961db09b84Saurel32 out:
397347dd79dSAlexander Graf     g_free(pci_map);
3981db09b84Saurel32 
39904088adbSLiu Yu     return ret;
4001db09b84Saurel32 }
4011db09b84Saurel32 
40228290f37SAlexander Graf typedef struct DeviceTreeParams {
4033ef96221SMarcel Apfelbaum     MachineState *machine;
40428290f37SAlexander Graf     PPCE500Params params;
40528290f37SAlexander Graf     hwaddr addr;
40628290f37SAlexander Graf     hwaddr initrd_base;
40728290f37SAlexander Graf     hwaddr initrd_size;
408903585deSAlexander Graf     hwaddr kernel_base;
409903585deSAlexander Graf     hwaddr kernel_size;
41028290f37SAlexander Graf } DeviceTreeParams;
41128290f37SAlexander Graf 
41228290f37SAlexander Graf static void ppce500_reset_device_tree(void *opaque)
41328290f37SAlexander Graf {
41428290f37SAlexander Graf     DeviceTreeParams *p = opaque;
4153812c71fSAlexander Graf     ppce500_load_device_tree(p->machine, &p->params, p->addr, p->initrd_base,
416903585deSAlexander Graf                              p->initrd_size, p->kernel_base, p->kernel_size,
417903585deSAlexander Graf                              false);
41828290f37SAlexander Graf }
41928290f37SAlexander Graf 
4203ef96221SMarcel Apfelbaum static int ppce500_prep_device_tree(MachineState *machine,
42128290f37SAlexander Graf                                     PPCE500Params *params,
42228290f37SAlexander Graf                                     hwaddr addr,
42328290f37SAlexander Graf                                     hwaddr initrd_base,
424903585deSAlexander Graf                                     hwaddr initrd_size,
425903585deSAlexander Graf                                     hwaddr kernel_base,
426903585deSAlexander Graf                                     hwaddr kernel_size)
42728290f37SAlexander Graf {
42828290f37SAlexander Graf     DeviceTreeParams *p = g_new(DeviceTreeParams, 1);
4293ef96221SMarcel Apfelbaum     p->machine = machine;
43028290f37SAlexander Graf     p->params = *params;
43128290f37SAlexander Graf     p->addr = addr;
43228290f37SAlexander Graf     p->initrd_base = initrd_base;
43328290f37SAlexander Graf     p->initrd_size = initrd_size;
434903585deSAlexander Graf     p->kernel_base = kernel_base;
435903585deSAlexander Graf     p->kernel_size = kernel_size;
43628290f37SAlexander Graf 
43728290f37SAlexander Graf     qemu_register_reset(ppce500_reset_device_tree, p);
43828290f37SAlexander Graf 
43928290f37SAlexander Graf     /* Issue the device tree loader once, so that we get the size of the blob */
4403ef96221SMarcel Apfelbaum     return ppce500_load_device_tree(machine, params, addr, initrd_base,
441903585deSAlexander Graf                                     initrd_size, kernel_base, kernel_size,
442903585deSAlexander Graf                                     true);
44328290f37SAlexander Graf }
44428290f37SAlexander Graf 
445cba2026aSAlexander Graf /* Create -kernel TLB entries for BookE.  */
446a8170e5eSAvi Kivity static inline hwaddr booke206_page_size_to_tlb(uint64_t size)
447d1e256feSAlexander Graf {
448cba2026aSAlexander Graf     return 63 - clz64(size >> 10);
449d1e256feSAlexander Graf }
450d1e256feSAlexander Graf 
451cefd3cdbSBharat Bhushan static int booke206_initial_map_tsize(CPUPPCState *env)
4523b989d49SAlexander Graf {
453cba2026aSAlexander Graf     struct boot_info *bi = env->load_info;
454cefd3cdbSBharat Bhushan     hwaddr dt_end;
455cba2026aSAlexander Graf     int ps;
4563b989d49SAlexander Graf 
457cba2026aSAlexander Graf     /* Our initial TLB entry needs to cover everything from 0 to
458cba2026aSAlexander Graf        the device tree top */
459cba2026aSAlexander Graf     dt_end = bi->dt_base + bi->dt_size;
460cba2026aSAlexander Graf     ps = booke206_page_size_to_tlb(dt_end) + 1;
461fb37c302SAlexander Graf     if (ps & 1) {
462fb37c302SAlexander Graf         /* e500v2 can only do even TLB size bits */
463fb37c302SAlexander Graf         ps++;
464fb37c302SAlexander Graf     }
465cefd3cdbSBharat Bhushan     return ps;
466cefd3cdbSBharat Bhushan }
467cefd3cdbSBharat Bhushan 
468cefd3cdbSBharat Bhushan static uint64_t mmubooke_initial_mapsize(CPUPPCState *env)
469cefd3cdbSBharat Bhushan {
470cefd3cdbSBharat Bhushan     int tsize;
471cefd3cdbSBharat Bhushan 
472cefd3cdbSBharat Bhushan     tsize = booke206_initial_map_tsize(env);
473cefd3cdbSBharat Bhushan     return (1ULL << 10 << tsize);
474cefd3cdbSBharat Bhushan }
475cefd3cdbSBharat Bhushan 
476cefd3cdbSBharat Bhushan static void mmubooke_create_initial_mapping(CPUPPCState *env)
477cefd3cdbSBharat Bhushan {
478cefd3cdbSBharat Bhushan     ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0);
479cefd3cdbSBharat Bhushan     hwaddr size;
480cefd3cdbSBharat Bhushan     int ps;
481cefd3cdbSBharat Bhushan 
482cefd3cdbSBharat Bhushan     ps = booke206_initial_map_tsize(env);
483cba2026aSAlexander Graf     size = (ps << MAS1_TSIZE_SHIFT);
484d1e256feSAlexander Graf     tlb->mas1 = MAS1_VALID | size;
485cba2026aSAlexander Graf     tlb->mas2 = 0;
486cba2026aSAlexander Graf     tlb->mas7_3 = 0;
487d1e256feSAlexander Graf     tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
48893dd5e85SScott Wood 
48993dd5e85SScott Wood     env->tlb_dirty = true;
4903b989d49SAlexander Graf }
4913b989d49SAlexander Graf 
492b3305981SScott Wood static void ppce500_cpu_reset_sec(void *opaque)
4935c145dacSAlexander Graf {
49438f92da6SAndreas Färber     PowerPCCPU *cpu = opaque;
495259186a7SAndreas Färber     CPUState *cs = CPU(cpu);
4965c145dacSAlexander Graf 
497259186a7SAndreas Färber     cpu_reset(cs);
4985c145dacSAlexander Graf 
4995c145dacSAlexander Graf     /* Secondary CPU starts in halted state for now. Needs to change when
5005c145dacSAlexander Graf        implementing non-kernel boot. */
501259186a7SAndreas Färber     cs->halted = 1;
50227103424SAndreas Färber     cs->exception_index = EXCP_HLT;
5033b989d49SAlexander Graf }
5043b989d49SAlexander Graf 
505b3305981SScott Wood static void ppce500_cpu_reset(void *opaque)
5063b989d49SAlexander Graf {
50738f92da6SAndreas Färber     PowerPCCPU *cpu = opaque;
508259186a7SAndreas Färber     CPUState *cs = CPU(cpu);
50938f92da6SAndreas Färber     CPUPPCState *env = &cpu->env;
5103b989d49SAlexander Graf     struct boot_info *bi = env->load_info;
5113b989d49SAlexander Graf 
512259186a7SAndreas Färber     cpu_reset(cs);
5133b989d49SAlexander Graf 
5143b989d49SAlexander Graf     /* Set initial guest state. */
515259186a7SAndreas Färber     cs->halted = 0;
5163b989d49SAlexander Graf     env->gpr[1] = (16<<20) - 8;
5173b989d49SAlexander Graf     env->gpr[3] = bi->dt_base;
518cefd3cdbSBharat Bhushan     env->gpr[4] = 0;
519cefd3cdbSBharat Bhushan     env->gpr[5] = 0;
520cefd3cdbSBharat Bhushan     env->gpr[6] = EPAPR_MAGIC;
521cefd3cdbSBharat Bhushan     env->gpr[7] = mmubooke_initial_mapsize(env);
522cefd3cdbSBharat Bhushan     env->gpr[8] = 0;
523cefd3cdbSBharat Bhushan     env->gpr[9] = 0;
5243b989d49SAlexander Graf     env->nip = bi->entry;
525cba2026aSAlexander Graf     mmubooke_create_initial_mapping(env);
5263b989d49SAlexander Graf }
5273b989d49SAlexander Graf 
528d85937e6SScott Wood static DeviceState *ppce500_init_mpic_qemu(PPCE500Params *params,
52982fc73b6SScott Wood                                            qemu_irq **irqs)
53082fc73b6SScott Wood {
53182fc73b6SScott Wood     DeviceState *dev;
53282fc73b6SScott Wood     SysBusDevice *s;
53382fc73b6SScott Wood     int i, j, k;
53482fc73b6SScott Wood 
535e1766344SAndreas Färber     dev = qdev_create(NULL, TYPE_OPENPIC);
53682fc73b6SScott Wood     qdev_prop_set_uint32(dev, "model", params->mpic_version);
537d85937e6SScott Wood     qdev_prop_set_uint32(dev, "nb_cpus", smp_cpus);
538d85937e6SScott Wood 
53982fc73b6SScott Wood     qdev_init_nofail(dev);
54082fc73b6SScott Wood     s = SYS_BUS_DEVICE(dev);
54182fc73b6SScott Wood 
54282fc73b6SScott Wood     k = 0;
54382fc73b6SScott Wood     for (i = 0; i < smp_cpus; i++) {
54482fc73b6SScott Wood         for (j = 0; j < OPENPIC_OUTPUT_NB; j++) {
54582fc73b6SScott Wood             sysbus_connect_irq(s, k++, irqs[i][j]);
54682fc73b6SScott Wood         }
54782fc73b6SScott Wood     }
54882fc73b6SScott Wood 
549d85937e6SScott Wood     return dev;
550d85937e6SScott Wood }
551d85937e6SScott Wood 
552d85937e6SScott Wood static DeviceState *ppce500_init_mpic_kvm(PPCE500Params *params,
553d85937e6SScott Wood                                           qemu_irq **irqs)
554d85937e6SScott Wood {
555d85937e6SScott Wood     DeviceState *dev;
556d85937e6SScott Wood     CPUState *cs;
557d85937e6SScott Wood     int r;
558d85937e6SScott Wood 
559dd49c038SAndreas Färber     dev = qdev_create(NULL, TYPE_KVM_OPENPIC);
560d85937e6SScott Wood     qdev_prop_set_uint32(dev, "model", params->mpic_version);
561d85937e6SScott Wood 
562d85937e6SScott Wood     r = qdev_init(dev);
563d85937e6SScott Wood     if (r) {
564d85937e6SScott Wood         return NULL;
565d85937e6SScott Wood     }
566d85937e6SScott Wood 
567bdc44640SAndreas Färber     CPU_FOREACH(cs) {
568d85937e6SScott Wood         if (kvm_openpic_connect_vcpu(dev, cs)) {
569d85937e6SScott Wood             fprintf(stderr, "%s: failed to connect vcpu to irqchip\n",
570d85937e6SScott Wood                     __func__);
571d85937e6SScott Wood             abort();
572d85937e6SScott Wood         }
573d85937e6SScott Wood     }
574d85937e6SScott Wood 
575d85937e6SScott Wood     return dev;
576d85937e6SScott Wood }
577d85937e6SScott Wood 
578d85937e6SScott Wood static qemu_irq *ppce500_init_mpic(PPCE500Params *params, MemoryRegion *ccsr,
579d85937e6SScott Wood                                    qemu_irq **irqs)
580d85937e6SScott Wood {
581d85937e6SScott Wood     qemu_irq *mpic;
582d85937e6SScott Wood     DeviceState *dev = NULL;
583d85937e6SScott Wood     SysBusDevice *s;
584d85937e6SScott Wood     int i;
585d85937e6SScott Wood 
586*aa2ac1daSPeter Crosthwaite     mpic = g_new0(qemu_irq, 256);
587d85937e6SScott Wood 
588d85937e6SScott Wood     if (kvm_enabled()) {
58936ad0e94SMarkus Armbruster         QemuOpts *machine_opts = qemu_get_machine_opts();
59036ad0e94SMarkus Armbruster         bool irqchip_allowed = qemu_opt_get_bool(machine_opts,
591d85937e6SScott Wood                                                 "kernel_irqchip", true);
59236ad0e94SMarkus Armbruster         bool irqchip_required = qemu_opt_get_bool(machine_opts,
593d85937e6SScott Wood                                                   "kernel_irqchip", false);
594d85937e6SScott Wood 
595d85937e6SScott Wood         if (irqchip_allowed) {
596d85937e6SScott Wood             dev = ppce500_init_mpic_kvm(params, irqs);
597d85937e6SScott Wood         }
598d85937e6SScott Wood 
599d85937e6SScott Wood         if (irqchip_required && !dev) {
600d85937e6SScott Wood             fprintf(stderr, "%s: irqchip requested but unavailable\n",
601d85937e6SScott Wood                     __func__);
602d85937e6SScott Wood             abort();
603d85937e6SScott Wood         }
604d85937e6SScott Wood     }
605d85937e6SScott Wood 
606d85937e6SScott Wood     if (!dev) {
607d85937e6SScott Wood         dev = ppce500_init_mpic_qemu(params, irqs);
608d85937e6SScott Wood     }
609d85937e6SScott Wood 
61082fc73b6SScott Wood     for (i = 0; i < 256; i++) {
61182fc73b6SScott Wood         mpic[i] = qdev_get_gpio_in(dev, i);
61282fc73b6SScott Wood     }
61382fc73b6SScott Wood 
614d85937e6SScott Wood     s = SYS_BUS_DEVICE(dev);
61582fc73b6SScott Wood     memory_region_add_subregion(ccsr, MPC8544_MPIC_REGS_OFFSET,
61682fc73b6SScott Wood                                 s->mmio[0].memory);
61782fc73b6SScott Wood 
61882fc73b6SScott Wood     return mpic;
61982fc73b6SScott Wood }
62082fc73b6SScott Wood 
6213ef96221SMarcel Apfelbaum void ppce500_init(MachineState *machine, PPCE500Params *params)
6221db09b84Saurel32 {
62339186d8aSRichard Henderson     MemoryRegion *address_space_mem = get_system_memory();
6242646c133SAvi Kivity     MemoryRegion *ram = g_new(MemoryRegion, 1);
6251db09b84Saurel32     PCIBus *pci_bus;
626e2684c0bSAndreas Färber     CPUPPCState *env = NULL;
6273812c71fSAlexander Graf     uint64_t loadaddr;
6283812c71fSAlexander Graf     hwaddr kernel_base = -1LL;
6293812c71fSAlexander Graf     int kernel_size = 0;
6303812c71fSAlexander Graf     hwaddr dt_base = 0;
6313812c71fSAlexander Graf     hwaddr initrd_base = 0;
6323812c71fSAlexander Graf     int initrd_size = 0;
6333812c71fSAlexander Graf     hwaddr cur_base = 0;
6343812c71fSAlexander Graf     char *filename;
6353812c71fSAlexander Graf     hwaddr bios_entry = 0;
6363812c71fSAlexander Graf     target_long bios_size;
6373812c71fSAlexander Graf     struct boot_info *boot_info;
6383812c71fSAlexander Graf     int dt_size;
63982fc73b6SScott Wood     int i;
640d575a6ceSBharat Bhushan     /* irq num for pin INTA, INTB, INTC and INTD is 1, 2, 3 and
641d575a6ceSBharat Bhushan      * 4 respectively */
642d575a6ceSBharat Bhushan     unsigned int pci_irq_nrs[PCI_NUM_PINS] = {1, 2, 3, 4};
643a915249fSAlexander Graf     qemu_irq **irqs, *mpic;
644be13cc7aSAlexander Graf     DeviceState *dev;
645e2684c0bSAndreas Färber     CPUPPCState *firstenv = NULL;
6463eddc1beSBharat Bhushan     MemoryRegion *ccsr_addr_space;
647dffb1dc2SBharat Bhushan     SysBusDevice *s;
6483eddc1beSBharat Bhushan     PPCE500CCSRState *ccsr;
6491db09b84Saurel32 
650e61c36d5SAlexander Graf     /* Setup CPUs */
6513ef96221SMarcel Apfelbaum     if (machine->cpu_model == NULL) {
6523ef96221SMarcel Apfelbaum         machine->cpu_model = "e500v2_v30";
653ef250db6SAlexander Graf     }
654ef250db6SAlexander Graf 
655a915249fSAlexander Graf     irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *));
656a915249fSAlexander Graf     irqs[0] = g_malloc0(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
657e61c36d5SAlexander Graf     for (i = 0; i < smp_cpus; i++) {
658397b457dSAndreas Färber         PowerPCCPU *cpu;
65955e5c285SAndreas Färber         CPUState *cs;
660e61c36d5SAlexander Graf         qemu_irq *input;
661397b457dSAndreas Färber 
6623ef96221SMarcel Apfelbaum         cpu = cpu_ppc_init(machine->cpu_model);
663397b457dSAndreas Färber         if (cpu == NULL) {
6641db09b84Saurel32             fprintf(stderr, "Unable to initialize CPU!\n");
6651db09b84Saurel32             exit(1);
6661db09b84Saurel32         }
667397b457dSAndreas Färber         env = &cpu->env;
66855e5c285SAndreas Färber         cs = CPU(cpu);
6691db09b84Saurel32 
670e61c36d5SAlexander Graf         if (!firstenv) {
671e61c36d5SAlexander Graf             firstenv = env;
672e61c36d5SAlexander Graf         }
673e61c36d5SAlexander Graf 
674a915249fSAlexander Graf         irqs[i] = irqs[0] + (i * OPENPIC_OUTPUT_NB);
675a915249fSAlexander Graf         input = (qemu_irq *)env->irq_inputs;
676a915249fSAlexander Graf         irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT];
677a915249fSAlexander Graf         irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT];
6786a450df9SAlexander Graf         env->spr_cb[SPR_BOOKE_PIR].default_value = cs->cpu_index = i;
67968c2dd70SAlexander Graf         env->mpic_iack = MPC8544_CCSRBAR_BASE +
680bd25922eSScott Wood                          MPC8544_MPIC_REGS_OFFSET + 0xa0;
681e61c36d5SAlexander Graf 
682a34a92b9SAndreas Färber         ppc_booke_timers_init(cpu, 400000000, PPC_TIMER_E500);
6833b989d49SAlexander Graf 
6843b989d49SAlexander Graf         /* Register reset handler */
6855c145dacSAlexander Graf         if (!i) {
6865c145dacSAlexander Graf             /* Primary CPU */
6875c145dacSAlexander Graf             struct boot_info *boot_info;
688e61c36d5SAlexander Graf             boot_info = g_malloc0(sizeof(struct boot_info));
689b3305981SScott Wood             qemu_register_reset(ppce500_cpu_reset, cpu);
690e61c36d5SAlexander Graf             env->load_info = boot_info;
6915c145dacSAlexander Graf         } else {
6925c145dacSAlexander Graf             /* Secondary CPUs */
693b3305981SScott Wood             qemu_register_reset(ppce500_cpu_reset_sec, cpu);
6945c145dacSAlexander Graf         }
695e61c36d5SAlexander Graf     }
696e61c36d5SAlexander Graf 
697e61c36d5SAlexander Graf     env = firstenv;
6983b989d49SAlexander Graf 
6991db09b84Saurel32     /* Fixup Memory size on a alignment boundary */
7001db09b84Saurel32     ram_size &= ~(RAM_SIZES_ALIGN - 1);
7013ef96221SMarcel Apfelbaum     machine->ram_size = ram_size;
7021db09b84Saurel32 
7031db09b84Saurel32     /* Register Memory */
704e938ba0cSShreyas B. Prabhu     memory_region_allocate_system_memory(ram, NULL, "mpc8544ds.ram", ram_size);
7052646c133SAvi Kivity     memory_region_add_subregion(address_space_mem, 0, ram);
7061db09b84Saurel32 
7073eddc1beSBharat Bhushan     dev = qdev_create(NULL, "e500-ccsr");
7083eddc1beSBharat Bhushan     object_property_add_child(qdev_get_machine(), "e500-ccsr",
7093eddc1beSBharat Bhushan                               OBJECT(dev), NULL);
7103eddc1beSBharat Bhushan     qdev_init_nofail(dev);
7113eddc1beSBharat Bhushan     ccsr = CCSR(dev);
7123eddc1beSBharat Bhushan     ccsr_addr_space = &ccsr->ccsr_space;
7133eddc1beSBharat Bhushan     memory_region_add_subregion(address_space_mem, MPC8544_CCSRBAR_BASE,
7143eddc1beSBharat Bhushan                                 ccsr_addr_space);
715dffb1dc2SBharat Bhushan 
71682fc73b6SScott Wood     mpic = ppce500_init_mpic(params, ccsr_addr_space, irqs);
7171db09b84Saurel32 
7181db09b84Saurel32     /* Serial */
7192d48377aSBlue Swirl     if (serial_hds[0]) {
7203eddc1beSBharat Bhushan         serial_mm_init(ccsr_addr_space, MPC8544_SERIAL0_REGS_OFFSET,
721cdbb912aSAlexander Graf                        0, mpic[42], 399193,
7222ff0c7c3SRichard Henderson                        serial_hds[0], DEVICE_BIG_ENDIAN);
7232d48377aSBlue Swirl     }
7241db09b84Saurel32 
7252d48377aSBlue Swirl     if (serial_hds[1]) {
7263eddc1beSBharat Bhushan         serial_mm_init(ccsr_addr_space, MPC8544_SERIAL1_REGS_OFFSET,
727cdbb912aSAlexander Graf                        0, mpic[42], 399193,
72859de4f98SBharat Bhushan                        serial_hds[1], DEVICE_BIG_ENDIAN);
7292d48377aSBlue Swirl     }
7301db09b84Saurel32 
731b0fb8423SAlexander Graf     /* General Utility device */
732dffb1dc2SBharat Bhushan     dev = qdev_create(NULL, "mpc8544-guts");
733dffb1dc2SBharat Bhushan     qdev_init_nofail(dev);
734dffb1dc2SBharat Bhushan     s = SYS_BUS_DEVICE(dev);
7353eddc1beSBharat Bhushan     memory_region_add_subregion(ccsr_addr_space, MPC8544_UTIL_OFFSET,
736dffb1dc2SBharat Bhushan                                 sysbus_mmio_get_region(s, 0));
737b0fb8423SAlexander Graf 
7381db09b84Saurel32     /* PCI */
739dffb1dc2SBharat Bhushan     dev = qdev_create(NULL, "e500-pcihost");
740492ec48dSAlexander Graf     qdev_prop_set_uint32(dev, "first_slot", params->pci_first_slot);
7413016dca0SBharat Bhushan     qdev_prop_set_uint32(dev, "first_pin_irq", pci_irq_nrs[0]);
742dffb1dc2SBharat Bhushan     qdev_init_nofail(dev);
743dffb1dc2SBharat Bhushan     s = SYS_BUS_DEVICE(dev);
744d575a6ceSBharat Bhushan     for (i = 0; i < PCI_NUM_PINS; i++) {
745d575a6ceSBharat Bhushan         sysbus_connect_irq(s, i, mpic[pci_irq_nrs[i]]);
746d575a6ceSBharat Bhushan     }
747d575a6ceSBharat Bhushan 
7483eddc1beSBharat Bhushan     memory_region_add_subregion(ccsr_addr_space, MPC8544_PCI_REGS_OFFSET,
749dffb1dc2SBharat Bhushan                                 sysbus_mmio_get_region(s, 0));
750dffb1dc2SBharat Bhushan 
751d461e3b9SAlexander Graf     pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
7521db09b84Saurel32     if (!pci_bus)
7531db09b84Saurel32         printf("couldn't create PCI controller!\n");
7541db09b84Saurel32 
7551356b98dSAndreas Färber     sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, MPC8544_PCI_IO);
7561db09b84Saurel32 
7571db09b84Saurel32     if (pci_bus) {
7581db09b84Saurel32         /* Register network interfaces. */
7591db09b84Saurel32         for (i = 0; i < nb_nics; i++) {
76029b358f9SDavid Gibson             pci_nic_init_nofail(&nd_table[i], pci_bus, "virtio", NULL);
7611db09b84Saurel32         }
7621db09b84Saurel32     }
7631db09b84Saurel32 
7645c145dacSAlexander Graf     /* Register spinning region */
7655c145dacSAlexander Graf     sysbus_create_simple("e500-spin", MPC8544_SPIN_BASE, NULL);
7665c145dacSAlexander Graf 
7673812c71fSAlexander Graf     if (cur_base < (32 * 1024 * 1024)) {
7683812c71fSAlexander Graf         /* u-boot occupies memory up to 32MB, so load blobs above */
7693812c71fSAlexander Graf         cur_base = (32 * 1024 * 1024);
7703812c71fSAlexander Graf     }
7713812c71fSAlexander Graf 
7721db09b84Saurel32     /* Load kernel. */
7733ef96221SMarcel Apfelbaum     if (machine->kernel_filename) {
7743812c71fSAlexander Graf         kernel_base = cur_base;
7753812c71fSAlexander Graf         kernel_size = load_image_targphys(machine->kernel_filename,
7763812c71fSAlexander Graf                                           cur_base,
7773812c71fSAlexander Graf                                           ram_size - cur_base);
7781db09b84Saurel32         if (kernel_size < 0) {
7791db09b84Saurel32             fprintf(stderr, "qemu: could not load kernel '%s'\n",
7803ef96221SMarcel Apfelbaum                     machine->kernel_filename);
7811db09b84Saurel32             exit(1);
7821db09b84Saurel32         }
783528e536eSAlexander Graf 
7843812c71fSAlexander Graf         cur_base += kernel_size;
7851db09b84Saurel32     }
7861db09b84Saurel32 
7871db09b84Saurel32     /* Load initrd. */
7883ef96221SMarcel Apfelbaum     if (machine->initrd_filename) {
789528e536eSAlexander Graf         initrd_base = (cur_base + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK;
7903ef96221SMarcel Apfelbaum         initrd_size = load_image_targphys(machine->initrd_filename, initrd_base,
791d7585251Spbrook                                           ram_size - initrd_base);
7921db09b84Saurel32 
7931db09b84Saurel32         if (initrd_size < 0) {
7941db09b84Saurel32             fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
7953ef96221SMarcel Apfelbaum                     machine->initrd_filename);
7961db09b84Saurel32             exit(1);
7971db09b84Saurel32         }
798528e536eSAlexander Graf 
799528e536eSAlexander Graf         cur_base = initrd_base + initrd_size;
8001db09b84Saurel32     }
8011db09b84Saurel32 
8023812c71fSAlexander Graf     /*
8033812c71fSAlexander Graf      * Smart firmware defaults ahead!
8043812c71fSAlexander Graf      *
8053812c71fSAlexander Graf      * We follow the following table to select which payload we execute.
8063812c71fSAlexander Graf      *
8073812c71fSAlexander Graf      *  -kernel | -bios | payload
8083812c71fSAlexander Graf      * ---------+-------+---------
8093812c71fSAlexander Graf      *     N    |   Y   | u-boot
8103812c71fSAlexander Graf      *     N    |   N   | u-boot
8113812c71fSAlexander Graf      *     Y    |   Y   | u-boot
8123812c71fSAlexander Graf      *     Y    |   N   | kernel
8133812c71fSAlexander Graf      *
8143812c71fSAlexander Graf      * This ensures backwards compatibility with how we used to expose
8153812c71fSAlexander Graf      * -kernel to users but allows them to run through u-boot as well.
8163812c71fSAlexander Graf      */
8173812c71fSAlexander Graf     if (bios_name == NULL) {
8183ef96221SMarcel Apfelbaum         if (machine->kernel_filename) {
8193812c71fSAlexander Graf             bios_name = machine->kernel_filename;
8203812c71fSAlexander Graf         } else {
8213812c71fSAlexander Graf             bios_name = "u-boot.e500";
8223812c71fSAlexander Graf         }
8233812c71fSAlexander Graf     }
8243812c71fSAlexander Graf     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
8253812c71fSAlexander Graf 
8263812c71fSAlexander Graf     bios_size = load_elf(filename, NULL, NULL, &bios_entry, &loadaddr, NULL,
8273812c71fSAlexander Graf                          1, ELF_MACHINE, 0);
8283812c71fSAlexander Graf     if (bios_size < 0) {
8293812c71fSAlexander Graf         /*
8303812c71fSAlexander Graf          * Hrm. No ELF image? Try a uImage, maybe someone is giving us an
8313812c71fSAlexander Graf          * ePAPR compliant kernel
8323812c71fSAlexander Graf          */
8333812c71fSAlexander Graf         kernel_size = load_uimage(filename, &bios_entry, &loadaddr, NULL);
8343812c71fSAlexander Graf         if (kernel_size < 0) {
8353812c71fSAlexander Graf             fprintf(stderr, "qemu: could not load firmware '%s'\n", filename);
8363812c71fSAlexander Graf             exit(1);
8373812c71fSAlexander Graf         }
8383812c71fSAlexander Graf     }
8393812c71fSAlexander Graf 
8403812c71fSAlexander Graf     /* Reserve space for dtb */
8413812c71fSAlexander Graf     dt_base = (loadaddr + bios_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
8425c145dacSAlexander Graf 
8433ef96221SMarcel Apfelbaum     dt_size = ppce500_prep_device_tree(machine, params, dt_base,
844903585deSAlexander Graf                                        initrd_base, initrd_size,
8453812c71fSAlexander Graf                                        kernel_base, kernel_size);
846cba2026aSAlexander Graf     if (dt_size < 0) {
8471db09b84Saurel32         fprintf(stderr, "couldn't load device tree\n");
8481db09b84Saurel32         exit(1);
8491db09b84Saurel32     }
850b8dec144SAlexander Graf     assert(dt_size < DTB_MAX_SIZE);
8511db09b84Saurel32 
852e61c36d5SAlexander Graf     boot_info = env->load_info;
8533812c71fSAlexander Graf     boot_info->entry = bios_entry;
8543b989d49SAlexander Graf     boot_info->dt_base = dt_base;
855cba2026aSAlexander Graf     boot_info->dt_size = dt_size;
8561db09b84Saurel32 
8573b989d49SAlexander Graf     if (kvm_enabled()) {
8581db09b84Saurel32         kvmppc_init();
8593b989d49SAlexander Graf     }
8601db09b84Saurel32 }
8613eddc1beSBharat Bhushan 
8623eddc1beSBharat Bhushan static int e500_ccsr_initfn(SysBusDevice *dev)
8633eddc1beSBharat Bhushan {
8643eddc1beSBharat Bhushan     PPCE500CCSRState *ccsr;
8653eddc1beSBharat Bhushan 
8663eddc1beSBharat Bhushan     ccsr = CCSR(dev);
86740c5dce9SPaolo Bonzini     memory_region_init(&ccsr->ccsr_space, OBJECT(ccsr), "e500-ccsr",
8683eddc1beSBharat Bhushan                        MPC8544_CCSRBAR_SIZE);
8693eddc1beSBharat Bhushan     return 0;
8703eddc1beSBharat Bhushan }
8713eddc1beSBharat Bhushan 
8723eddc1beSBharat Bhushan static void e500_ccsr_class_init(ObjectClass *klass, void *data)
8733eddc1beSBharat Bhushan {
8743eddc1beSBharat Bhushan     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
8753eddc1beSBharat Bhushan     k->init = e500_ccsr_initfn;
8763eddc1beSBharat Bhushan }
8773eddc1beSBharat Bhushan 
8783eddc1beSBharat Bhushan static const TypeInfo e500_ccsr_info = {
8793eddc1beSBharat Bhushan     .name          = TYPE_CCSR,
8803eddc1beSBharat Bhushan     .parent        = TYPE_SYS_BUS_DEVICE,
8813eddc1beSBharat Bhushan     .instance_size = sizeof(PPCE500CCSRState),
8823eddc1beSBharat Bhushan     .class_init    = e500_ccsr_class_init,
8833eddc1beSBharat Bhushan };
8843eddc1beSBharat Bhushan 
8853eddc1beSBharat Bhushan static void e500_register_types(void)
8863eddc1beSBharat Bhushan {
8873eddc1beSBharat Bhushan     type_register_static(&e500_ccsr_info);
8883eddc1beSBharat Bhushan }
8893eddc1beSBharat Bhushan 
8903eddc1beSBharat Bhushan type_init(e500_register_types)
891