xref: /qemu/hw/ppc/e500.c (revision 0f20ba62c35e6a779ba4ea00616192ef2abb6896)
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"
421db09b84Saurel32 #define UIMAGE_LOAD_BASE           0
439dd5eba1SScott Wood #define DTC_LOAD_PAD               0x1800000
4475bb6589SLiu Yu #define DTC_PAD_MASK               0xFFFFF
45b8dec144SAlexander Graf #define DTB_MAX_SIZE               (8 * 1024 * 1024)
4675bb6589SLiu Yu #define INITRD_LOAD_PAD            0x2000000
4775bb6589SLiu Yu #define INITRD_PAD_MASK            0xFFFFFF
481db09b84Saurel32 
491db09b84Saurel32 #define RAM_SIZES_ALIGN            (64UL << 20)
501db09b84Saurel32 
51b3305981SScott Wood /* TODO: parameterize */
52ed2bc496SAlexander Graf #define MPC8544_CCSRBAR_BASE       0xE0000000ULL
53ed2bc496SAlexander Graf #define MPC8544_CCSRBAR_SIZE       0x00100000ULL
54dffb1dc2SBharat Bhushan #define MPC8544_MPIC_REGS_OFFSET   0x40000ULL
55a911b7a9SAlexander Graf #define MPC8544_MSI_REGS_OFFSET   0x41600ULL
56dffb1dc2SBharat Bhushan #define MPC8544_SERIAL0_REGS_OFFSET 0x4500ULL
57dffb1dc2SBharat Bhushan #define MPC8544_SERIAL1_REGS_OFFSET 0x4600ULL
58dffb1dc2SBharat Bhushan #define MPC8544_PCI_REGS_OFFSET    0x8000ULL
59dffb1dc2SBharat Bhushan #define MPC8544_PCI_REGS_BASE      (MPC8544_CCSRBAR_BASE + \
60dffb1dc2SBharat Bhushan                                     MPC8544_PCI_REGS_OFFSET)
61ed2bc496SAlexander Graf #define MPC8544_PCI_REGS_SIZE      0x1000ULL
62ed2bc496SAlexander Graf #define MPC8544_PCI_IO             0xE1000000ULL
63dffb1dc2SBharat Bhushan #define MPC8544_UTIL_OFFSET        0xe0000ULL
64ed2bc496SAlexander Graf #define MPC8544_SPIN_BASE          0xEF000000ULL
651db09b84Saurel32 
663b989d49SAlexander Graf struct boot_info
673b989d49SAlexander Graf {
683b989d49SAlexander Graf     uint32_t dt_base;
69cba2026aSAlexander Graf     uint32_t dt_size;
703b989d49SAlexander Graf     uint32_t entry;
713b989d49SAlexander Graf };
723b989d49SAlexander Graf 
73347dd79dSAlexander Graf static uint32_t *pci_map_create(void *fdt, uint32_t mpic, int first_slot,
74347dd79dSAlexander Graf                                 int nr_slots, int *len)
750dbc0798SAlexander Graf {
76347dd79dSAlexander Graf     int i = 0;
77347dd79dSAlexander Graf     int slot;
78347dd79dSAlexander Graf     int pci_irq;
799e2c1298SAlexander Graf     int host_irq;
80347dd79dSAlexander Graf     int last_slot = first_slot + nr_slots;
81347dd79dSAlexander Graf     uint32_t *pci_map;
820dbc0798SAlexander Graf 
83347dd79dSAlexander Graf     *len = nr_slots * 4 * 7 * sizeof(uint32_t);
84347dd79dSAlexander Graf     pci_map = g_malloc(*len);
85347dd79dSAlexander Graf 
86347dd79dSAlexander Graf     for (slot = first_slot; slot < last_slot; slot++) {
87347dd79dSAlexander Graf         for (pci_irq = 0; pci_irq < 4; pci_irq++) {
88347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(slot << 11);
89347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(0x0);
90347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(0x0);
91347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(pci_irq + 1);
92347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(mpic);
939e2c1298SAlexander Graf             host_irq = ppce500_pci_map_irq_slot(slot, pci_irq);
949e2c1298SAlexander Graf             pci_map[i++] = cpu_to_be32(host_irq + 1);
95347dd79dSAlexander Graf             pci_map[i++] = cpu_to_be32(0x1);
960dbc0798SAlexander Graf         }
970dbc0798SAlexander Graf     }
980dbc0798SAlexander Graf 
99347dd79dSAlexander Graf     assert((i * sizeof(uint32_t)) == *len);
100347dd79dSAlexander Graf 
101347dd79dSAlexander Graf     return pci_map;
102347dd79dSAlexander Graf }
103347dd79dSAlexander Graf 
104a053a7ceSAlexander Graf static void dt_serial_create(void *fdt, unsigned long long offset,
105a053a7ceSAlexander Graf                              const char *soc, const char *mpic,
106a053a7ceSAlexander Graf                              const char *alias, int idx, bool defcon)
107a053a7ceSAlexander Graf {
108a053a7ceSAlexander Graf     char ser[128];
109a053a7ceSAlexander Graf 
110a053a7ceSAlexander Graf     snprintf(ser, sizeof(ser), "%s/serial@%llx", soc, offset);
1115a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, ser);
1125a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, ser, "device_type", "serial");
1135a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, ser, "compatible", "ns16550");
1145a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, ser, "reg", offset, 0x100);
1155a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, ser, "cell-index", idx);
1165a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, ser, "clock-frequency", 0);
1175a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, ser, "interrupts", 42, 2);
1185a4348d1SPeter Crosthwaite     qemu_fdt_setprop_phandle(fdt, ser, "interrupt-parent", mpic);
1195a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, "/aliases", alias, ser);
120a053a7ceSAlexander Graf 
121a053a7ceSAlexander Graf     if (defcon) {
1225a4348d1SPeter Crosthwaite         qemu_fdt_setprop_string(fdt, "/chosen", "linux,stdout-path", ser);
123a053a7ceSAlexander Graf     }
124a053a7ceSAlexander Graf }
125a053a7ceSAlexander Graf 
12628290f37SAlexander Graf static int ppce500_load_device_tree(QEMUMachineInitArgs *args,
127e6eaabebSScott Wood                                     PPCE500Params *params,
128a8170e5eSAvi Kivity                                     hwaddr addr,
129a8170e5eSAvi Kivity                                     hwaddr initrd_base,
13028290f37SAlexander Graf                                     hwaddr initrd_size,
13128290f37SAlexander Graf                                     bool dry_run)
1321db09b84Saurel32 {
13328290f37SAlexander Graf     CPUPPCState *env = first_cpu->env_ptr;
134dbf916d8SAurelien Jarno     int ret = -1;
13592238367SMarkus Armbruster     uint64_t mem_reg_property[] = { 0, cpu_to_be64(args->ram_size) };
1367ec632b4Spbrook     int fdt_size;
137dbf916d8SAurelien Jarno     void *fdt;
1385de6b46dSAlexander Graf     uint8_t hypercall[16];
139911d6e7aSAlexander Graf     uint32_t clock_freq = 400000000;
140911d6e7aSAlexander Graf     uint32_t tb_freq = 400000000;
141621d05e3SAlexander Graf     int i;
142ebb9518aSAlexander Graf     char compatible_sb[] = "fsl,mpc8544-immr\0simple-bus";
1435da96624SAlexander Graf     char soc[128];
14419ac9deaSAlexander Graf     char mpic[128];
14519ac9deaSAlexander Graf     uint32_t mpic_ph;
146a911b7a9SAlexander Graf     uint32_t msi_ph;
147f5038483SAlexander Graf     char gutil[128];
1480dbc0798SAlexander Graf     char pci[128];
149a911b7a9SAlexander Graf     char msi[128];
150347dd79dSAlexander Graf     uint32_t *pci_map = NULL;
151347dd79dSAlexander Graf     int len;
1523627757eSAlexander Graf     uint32_t pci_ranges[14] =
1533627757eSAlexander Graf         {
1543627757eSAlexander Graf             0x2000000, 0x0, 0xc0000000,
1553627757eSAlexander Graf             0x0, 0xc0000000,
1563627757eSAlexander Graf             0x0, 0x20000000,
1573627757eSAlexander Graf 
1583627757eSAlexander Graf             0x1000000, 0x0, 0x0,
1593627757eSAlexander Graf             0x0, 0xe1000000,
1603627757eSAlexander Graf             0x0, 0x10000,
1613627757eSAlexander Graf         };
1622ff3de68SMarkus Armbruster     QemuOpts *machine_opts = qemu_get_machine_opts();
1632ff3de68SMarkus Armbruster     const char *dtb_file = qemu_opt_get(machine_opts, "dtb");
1642ff3de68SMarkus Armbruster     const char *toplevel_compat = qemu_opt_get(machine_opts, "dt_compatible");
165d1b93565SAlexander Graf 
166d1b93565SAlexander Graf     if (dtb_file) {
167d1b93565SAlexander Graf         char *filename;
168d1b93565SAlexander Graf         filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_file);
169d1b93565SAlexander Graf         if (!filename) {
170d1b93565SAlexander Graf             goto out;
171d1b93565SAlexander Graf         }
172d1b93565SAlexander Graf 
173d1b93565SAlexander Graf         fdt = load_device_tree(filename, &fdt_size);
174d1b93565SAlexander Graf         if (!fdt) {
175d1b93565SAlexander Graf             goto out;
176d1b93565SAlexander Graf         }
177d1b93565SAlexander Graf         goto done;
178d1b93565SAlexander Graf     }
1791db09b84Saurel32 
1802636fcb6SAlexander Graf     fdt = create_device_tree(&fdt_size);
1815cea8590SPaul Brook     if (fdt == NULL) {
1825cea8590SPaul Brook         goto out;
1835cea8590SPaul Brook     }
1841db09b84Saurel32 
1851db09b84Saurel32     /* Manipulate device tree in memory. */
1865a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 2);
1875a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 2);
18851b852b7SAlexander Graf 
1895a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, "/memory");
1905a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, "/memory", "device_type", "memory");
1915a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, "/memory", "reg", mem_reg_property,
1921db09b84Saurel32                      sizeof(mem_reg_property));
1931db09b84Saurel32 
1945a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, "/chosen");
1953b989d49SAlexander Graf     if (initrd_size) {
1965a4348d1SPeter Crosthwaite         ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start",
1971db09b84Saurel32                                     initrd_base);
1983b989d49SAlexander Graf         if (ret < 0) {
1991db09b84Saurel32             fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
2003b989d49SAlexander Graf         }
2011db09b84Saurel32 
2025a4348d1SPeter Crosthwaite         ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
2031db09b84Saurel32                                     (initrd_base + initrd_size));
2043b989d49SAlexander Graf         if (ret < 0) {
2051db09b84Saurel32             fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
2063b989d49SAlexander Graf         }
2073b989d49SAlexander Graf     }
2081db09b84Saurel32 
2095a4348d1SPeter Crosthwaite     ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
21092238367SMarkus Armbruster                                       args->kernel_cmdline);
2111db09b84Saurel32     if (ret < 0)
2121db09b84Saurel32         fprintf(stderr, "couldn't set /chosen/bootargs\n");
2131db09b84Saurel32 
2141db09b84Saurel32     if (kvm_enabled()) {
215911d6e7aSAlexander Graf         /* Read out host's frequencies */
216911d6e7aSAlexander Graf         clock_freq = kvmppc_get_clockfreq();
217911d6e7aSAlexander Graf         tb_freq = kvmppc_get_tbfreq();
2185de6b46dSAlexander Graf 
2195de6b46dSAlexander Graf         /* indicate KVM hypercall interface */
2205a4348d1SPeter Crosthwaite         qemu_fdt_add_subnode(fdt, "/hypervisor");
2215a4348d1SPeter Crosthwaite         qemu_fdt_setprop_string(fdt, "/hypervisor", "compatible",
2225de6b46dSAlexander Graf                                 "linux,kvm");
2235de6b46dSAlexander Graf         kvmppc_get_hypercall(env, hypercall, sizeof(hypercall));
2245a4348d1SPeter Crosthwaite         qemu_fdt_setprop(fdt, "/hypervisor", "hcall-instructions",
2255de6b46dSAlexander Graf                          hypercall, sizeof(hypercall));
2261a61a9aeSStuart Yoder         /* if KVM supports the idle hcall, set property indicating this */
2271a61a9aeSStuart Yoder         if (kvmppc_get_hasidle(env)) {
2285a4348d1SPeter Crosthwaite             qemu_fdt_setprop(fdt, "/hypervisor", "has-idle", NULL, 0);
2291a61a9aeSStuart Yoder         }
2301db09b84Saurel32     }
2311db09b84Saurel32 
232625e665bSAlexander Graf     /* Create CPU nodes */
2335a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, "/cpus");
2345a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 1);
2355a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0);
236625e665bSAlexander Graf 
2371e3debf0SAlexander Graf     /* We need to generate the cpu nodes in reverse order, so Linux can pick
2381e3debf0SAlexander Graf        the first node as boot node and be happy */
2391e3debf0SAlexander Graf     for (i = smp_cpus - 1; i >= 0; i--) {
240440c8152SAndreas Färber         CPUState *cpu;
241*0f20ba62SAlexey Kardashevskiy         PowerPCCPU *pcpu;
242621d05e3SAlexander Graf         char cpu_name[128];
2431d2e5c52SAlexander Graf         uint64_t cpu_release_addr = MPC8544_SPIN_BASE + (i * 0x20);
24410f25a46SAlexander Graf 
245440c8152SAndreas Färber         cpu = qemu_get_cpu(i);
24655e5c285SAndreas Färber         if (cpu == NULL) {
2471e3debf0SAlexander Graf             continue;
2481e3debf0SAlexander Graf         }
249440c8152SAndreas Färber         env = cpu->env_ptr;
250*0f20ba62SAlexey Kardashevskiy         pcpu = POWERPC_CPU(cpu);
2511e3debf0SAlexander Graf 
25255e5c285SAndreas Färber         snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x",
253*0f20ba62SAlexey Kardashevskiy                  ppc_get_vcpu_dt_id(pcpu));
2545a4348d1SPeter Crosthwaite         qemu_fdt_add_subnode(fdt, cpu_name);
2555a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq);
2565a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq);
2575a4348d1SPeter Crosthwaite         qemu_fdt_setprop_string(fdt, cpu_name, "device_type", "cpu");
258*0f20ba62SAlexey Kardashevskiy         qemu_fdt_setprop_cell(fdt, cpu_name, "reg",
259*0f20ba62SAlexey Kardashevskiy                               ppc_get_vcpu_dt_id(pcpu));
2605a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-line-size",
2611e3debf0SAlexander Graf                               env->dcache_line_size);
2625a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-line-size",
2631e3debf0SAlexander Graf                               env->icache_line_size);
2645a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-size", 0x8000);
2655a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-size", 0x8000);
2665a4348d1SPeter Crosthwaite         qemu_fdt_setprop_cell(fdt, cpu_name, "bus-frequency", 0);
26755e5c285SAndreas Färber         if (cpu->cpu_index) {
2685a4348d1SPeter Crosthwaite             qemu_fdt_setprop_string(fdt, cpu_name, "status", "disabled");
2695a4348d1SPeter Crosthwaite             qemu_fdt_setprop_string(fdt, cpu_name, "enable-method",
2705a4348d1SPeter Crosthwaite                                     "spin-table");
2715a4348d1SPeter Crosthwaite             qemu_fdt_setprop_u64(fdt, cpu_name, "cpu-release-addr",
2721d2e5c52SAlexander Graf                                  cpu_release_addr);
2731e3debf0SAlexander Graf         } else {
2745a4348d1SPeter Crosthwaite             qemu_fdt_setprop_string(fdt, cpu_name, "status", "okay");
2751e3debf0SAlexander Graf         }
2761db09b84Saurel32     }
2771db09b84Saurel32 
2785a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, "/aliases");
2795da96624SAlexander Graf     /* XXX These should go into their respective devices' code */
280ed2bc496SAlexander Graf     snprintf(soc, sizeof(soc), "/soc@%llx", MPC8544_CCSRBAR_BASE);
2815a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, soc);
2825a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, soc, "device_type", "soc");
2835a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, soc, "compatible", compatible_sb,
284ebb9518aSAlexander Graf                      sizeof(compatible_sb));
2855a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, soc, "#address-cells", 1);
2865a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, soc, "#size-cells", 1);
2875a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, soc, "ranges", 0x0,
2883627757eSAlexander Graf                            MPC8544_CCSRBAR_BASE >> 32, MPC8544_CCSRBAR_BASE,
2895da96624SAlexander Graf                            MPC8544_CCSRBAR_SIZE);
2905da96624SAlexander Graf     /* XXX should contain a reasonable value */
2915a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, soc, "bus-frequency", 0);
2925da96624SAlexander Graf 
293dffb1dc2SBharat Bhushan     snprintf(mpic, sizeof(mpic), "%s/pic@%llx", soc, MPC8544_MPIC_REGS_OFFSET);
2945a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, mpic);
2955a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, mpic, "device_type", "open-pic");
2965a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, mpic, "compatible", "fsl,mpic");
2975a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_OFFSET,
298dffb1dc2SBharat Bhushan                            0x40000);
2995a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, mpic, "#address-cells", 0);
3005a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, mpic, "#interrupt-cells", 2);
3015a4348d1SPeter Crosthwaite     mpic_ph = qemu_fdt_alloc_phandle(fdt);
3025a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, mpic, "phandle", mpic_ph);
3035a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, mpic, "linux,phandle", mpic_ph);
3045a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, mpic, "interrupt-controller", NULL, 0);
30519ac9deaSAlexander Graf 
3060cfc6e8dSAlexander Graf     /*
3070cfc6e8dSAlexander Graf      * We have to generate ser1 first, because Linux takes the first
3080cfc6e8dSAlexander Graf      * device it finds in the dt as serial output device. And we generate
3090cfc6e8dSAlexander Graf      * devices in reverse order to the dt.
3100cfc6e8dSAlexander Graf      */
311dffb1dc2SBharat Bhushan     dt_serial_create(fdt, MPC8544_SERIAL1_REGS_OFFSET,
312a053a7ceSAlexander Graf                      soc, mpic, "serial1", 1, false);
313dffb1dc2SBharat Bhushan     dt_serial_create(fdt, MPC8544_SERIAL0_REGS_OFFSET,
314a053a7ceSAlexander Graf                      soc, mpic, "serial0", 0, true);
3150cfc6e8dSAlexander Graf 
316ed2bc496SAlexander Graf     snprintf(gutil, sizeof(gutil), "%s/global-utilities@%llx", soc,
317dffb1dc2SBharat Bhushan              MPC8544_UTIL_OFFSET);
3185a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, gutil);
3195a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, gutil, "compatible", "fsl,mpc8544-guts");
3205a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, gutil, "reg", MPC8544_UTIL_OFFSET, 0x1000);
3215a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, gutil, "fsl,has-rstcr", NULL, 0);
322f5038483SAlexander Graf 
323a911b7a9SAlexander Graf     snprintf(msi, sizeof(msi), "/%s/msi@%llx", soc, MPC8544_MSI_REGS_OFFSET);
3245a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, msi);
3255a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, msi, "compatible", "fsl,mpic-msi");
3265a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, msi, "reg", MPC8544_MSI_REGS_OFFSET, 0x200);
3275a4348d1SPeter Crosthwaite     msi_ph = qemu_fdt_alloc_phandle(fdt);
3285a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, msi, "msi-available-ranges", 0x0, 0x100);
3295a4348d1SPeter Crosthwaite     qemu_fdt_setprop_phandle(fdt, msi, "interrupt-parent", mpic);
3305a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, msi, "interrupts",
331a911b7a9SAlexander Graf         0xe0, 0x0,
332a911b7a9SAlexander Graf         0xe1, 0x0,
333a911b7a9SAlexander Graf         0xe2, 0x0,
334a911b7a9SAlexander Graf         0xe3, 0x0,
335a911b7a9SAlexander Graf         0xe4, 0x0,
336a911b7a9SAlexander Graf         0xe5, 0x0,
337a911b7a9SAlexander Graf         0xe6, 0x0,
338a911b7a9SAlexander Graf         0xe7, 0x0);
3395a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, msi, "phandle", msi_ph);
3405a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, msi, "linux,phandle", msi_ph);
341a911b7a9SAlexander Graf 
342ed2bc496SAlexander Graf     snprintf(pci, sizeof(pci), "/pci@%llx", MPC8544_PCI_REGS_BASE);
3435a4348d1SPeter Crosthwaite     qemu_fdt_add_subnode(fdt, pci);
3445a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "cell-index", 0);
3455a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, pci, "compatible", "fsl,mpc8540-pci");
3465a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, pci, "device_type", "pci");
3475a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, pci, "interrupt-map-mask", 0xf800, 0x0,
3480dbc0798SAlexander Graf                            0x0, 0x7);
3495a4348d1SPeter Crosthwaite     pci_map = pci_map_create(fdt, qemu_fdt_get_phandle(fdt, mpic),
350492ec48dSAlexander Graf                              params->pci_first_slot, params->pci_nr_slots,
351492ec48dSAlexander Graf                              &len);
3525a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, pci, "interrupt-map", pci_map, len);
3535a4348d1SPeter Crosthwaite     qemu_fdt_setprop_phandle(fdt, pci, "interrupt-parent", mpic);
3545a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, pci, "interrupts", 24, 2);
3555a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, pci, "bus-range", 0, 255);
3563627757eSAlexander Graf     for (i = 0; i < 14; i++) {
3570dbc0798SAlexander Graf         pci_ranges[i] = cpu_to_be32(pci_ranges[i]);
3580dbc0798SAlexander Graf     }
3595a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "fsl,msi", msi_ph);
3605a4348d1SPeter Crosthwaite     qemu_fdt_setprop(fdt, pci, "ranges", pci_ranges, sizeof(pci_ranges));
3615a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cells(fdt, pci, "reg", MPC8544_PCI_REGS_BASE >> 32,
3623627757eSAlexander Graf                            MPC8544_PCI_REGS_BASE, 0, 0x1000);
3635a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "clock-frequency", 66666666);
3645a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "#interrupt-cells", 1);
3655a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "#size-cells", 2);
3665a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, pci, "#address-cells", 3);
3675a4348d1SPeter Crosthwaite     qemu_fdt_setprop_string(fdt, "/aliases", "pci0", pci);
3680dbc0798SAlexander Graf 
369e6eaabebSScott Wood     params->fixup_devtree(params, fdt);
370e6eaabebSScott Wood 
371e6eaabebSScott Wood     if (toplevel_compat) {
3725a4348d1SPeter Crosthwaite         qemu_fdt_setprop(fdt, "/", "compatible", toplevel_compat,
373e6eaabebSScott Wood                          strlen(toplevel_compat) + 1);
374e6eaabebSScott Wood     }
375e6eaabebSScott Wood 
376d1b93565SAlexander Graf done:
37728290f37SAlexander Graf     if (!dry_run) {
3785a4348d1SPeter Crosthwaite         qemu_fdt_dumpdtb(fdt, fdt_size);
37928290f37SAlexander Graf         cpu_physical_memory_write(addr, fdt, fdt_size);
380cba2026aSAlexander Graf     }
381cba2026aSAlexander Graf     ret = fdt_size;
3827ec632b4Spbrook 
3831db09b84Saurel32 out:
384347dd79dSAlexander Graf     g_free(pci_map);
3851db09b84Saurel32 
38604088adbSLiu Yu     return ret;
3871db09b84Saurel32 }
3881db09b84Saurel32 
38928290f37SAlexander Graf typedef struct DeviceTreeParams {
39028290f37SAlexander Graf     QEMUMachineInitArgs args;
39128290f37SAlexander Graf     PPCE500Params params;
39228290f37SAlexander Graf     hwaddr addr;
39328290f37SAlexander Graf     hwaddr initrd_base;
39428290f37SAlexander Graf     hwaddr initrd_size;
39528290f37SAlexander Graf } DeviceTreeParams;
39628290f37SAlexander Graf 
39728290f37SAlexander Graf static void ppce500_reset_device_tree(void *opaque)
39828290f37SAlexander Graf {
39928290f37SAlexander Graf     DeviceTreeParams *p = opaque;
40028290f37SAlexander Graf     ppce500_load_device_tree(&p->args, &p->params, p->addr, p->initrd_base,
40128290f37SAlexander Graf                              p->initrd_size, false);
40228290f37SAlexander Graf }
40328290f37SAlexander Graf 
40428290f37SAlexander Graf static int ppce500_prep_device_tree(QEMUMachineInitArgs *args,
40528290f37SAlexander Graf                                     PPCE500Params *params,
40628290f37SAlexander Graf                                     hwaddr addr,
40728290f37SAlexander Graf                                     hwaddr initrd_base,
40828290f37SAlexander Graf                                     hwaddr initrd_size)
40928290f37SAlexander Graf {
41028290f37SAlexander Graf     DeviceTreeParams *p = g_new(DeviceTreeParams, 1);
41128290f37SAlexander Graf     p->args = *args;
41228290f37SAlexander Graf     p->params = *params;
41328290f37SAlexander Graf     p->addr = addr;
41428290f37SAlexander Graf     p->initrd_base = initrd_base;
41528290f37SAlexander Graf     p->initrd_size = initrd_size;
41628290f37SAlexander Graf 
41728290f37SAlexander Graf     qemu_register_reset(ppce500_reset_device_tree, p);
41828290f37SAlexander Graf 
41928290f37SAlexander Graf     /* Issue the device tree loader once, so that we get the size of the blob */
42028290f37SAlexander Graf     return ppce500_load_device_tree(args, params, addr, initrd_base,
42128290f37SAlexander Graf                                     initrd_size, true);
42228290f37SAlexander Graf }
42328290f37SAlexander Graf 
424cba2026aSAlexander Graf /* Create -kernel TLB entries for BookE.  */
425a8170e5eSAvi Kivity static inline hwaddr booke206_page_size_to_tlb(uint64_t size)
426d1e256feSAlexander Graf {
427cba2026aSAlexander Graf     return 63 - clz64(size >> 10);
428d1e256feSAlexander Graf }
429d1e256feSAlexander Graf 
430cefd3cdbSBharat Bhushan static int booke206_initial_map_tsize(CPUPPCState *env)
4313b989d49SAlexander Graf {
432cba2026aSAlexander Graf     struct boot_info *bi = env->load_info;
433cefd3cdbSBharat Bhushan     hwaddr dt_end;
434cba2026aSAlexander Graf     int ps;
4353b989d49SAlexander Graf 
436cba2026aSAlexander Graf     /* Our initial TLB entry needs to cover everything from 0 to
437cba2026aSAlexander Graf        the device tree top */
438cba2026aSAlexander Graf     dt_end = bi->dt_base + bi->dt_size;
439cba2026aSAlexander Graf     ps = booke206_page_size_to_tlb(dt_end) + 1;
440fb37c302SAlexander Graf     if (ps & 1) {
441fb37c302SAlexander Graf         /* e500v2 can only do even TLB size bits */
442fb37c302SAlexander Graf         ps++;
443fb37c302SAlexander Graf     }
444cefd3cdbSBharat Bhushan     return ps;
445cefd3cdbSBharat Bhushan }
446cefd3cdbSBharat Bhushan 
447cefd3cdbSBharat Bhushan static uint64_t mmubooke_initial_mapsize(CPUPPCState *env)
448cefd3cdbSBharat Bhushan {
449cefd3cdbSBharat Bhushan     int tsize;
450cefd3cdbSBharat Bhushan 
451cefd3cdbSBharat Bhushan     tsize = booke206_initial_map_tsize(env);
452cefd3cdbSBharat Bhushan     return (1ULL << 10 << tsize);
453cefd3cdbSBharat Bhushan }
454cefd3cdbSBharat Bhushan 
455cefd3cdbSBharat Bhushan static void mmubooke_create_initial_mapping(CPUPPCState *env)
456cefd3cdbSBharat Bhushan {
457cefd3cdbSBharat Bhushan     ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0);
458cefd3cdbSBharat Bhushan     hwaddr size;
459cefd3cdbSBharat Bhushan     int ps;
460cefd3cdbSBharat Bhushan 
461cefd3cdbSBharat Bhushan     ps = booke206_initial_map_tsize(env);
462cba2026aSAlexander Graf     size = (ps << MAS1_TSIZE_SHIFT);
463d1e256feSAlexander Graf     tlb->mas1 = MAS1_VALID | size;
464cba2026aSAlexander Graf     tlb->mas2 = 0;
465cba2026aSAlexander Graf     tlb->mas7_3 = 0;
466d1e256feSAlexander Graf     tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
46793dd5e85SScott Wood 
46893dd5e85SScott Wood     env->tlb_dirty = true;
4693b989d49SAlexander Graf }
4703b989d49SAlexander Graf 
471b3305981SScott Wood static void ppce500_cpu_reset_sec(void *opaque)
4725c145dacSAlexander Graf {
47338f92da6SAndreas Färber     PowerPCCPU *cpu = opaque;
474259186a7SAndreas Färber     CPUState *cs = CPU(cpu);
47538f92da6SAndreas Färber     CPUPPCState *env = &cpu->env;
4765c145dacSAlexander Graf 
477259186a7SAndreas Färber     cpu_reset(cs);
4785c145dacSAlexander Graf 
4795c145dacSAlexander Graf     /* Secondary CPU starts in halted state for now. Needs to change when
4805c145dacSAlexander Graf        implementing non-kernel boot. */
481259186a7SAndreas Färber     cs->halted = 1;
4825c145dacSAlexander Graf     env->exception_index = EXCP_HLT;
4833b989d49SAlexander Graf }
4843b989d49SAlexander Graf 
485b3305981SScott Wood static void ppce500_cpu_reset(void *opaque)
4863b989d49SAlexander Graf {
48738f92da6SAndreas Färber     PowerPCCPU *cpu = opaque;
488259186a7SAndreas Färber     CPUState *cs = CPU(cpu);
48938f92da6SAndreas Färber     CPUPPCState *env = &cpu->env;
4903b989d49SAlexander Graf     struct boot_info *bi = env->load_info;
4913b989d49SAlexander Graf 
492259186a7SAndreas Färber     cpu_reset(cs);
4933b989d49SAlexander Graf 
4943b989d49SAlexander Graf     /* Set initial guest state. */
495259186a7SAndreas Färber     cs->halted = 0;
4963b989d49SAlexander Graf     env->gpr[1] = (16<<20) - 8;
4973b989d49SAlexander Graf     env->gpr[3] = bi->dt_base;
498cefd3cdbSBharat Bhushan     env->gpr[4] = 0;
499cefd3cdbSBharat Bhushan     env->gpr[5] = 0;
500cefd3cdbSBharat Bhushan     env->gpr[6] = EPAPR_MAGIC;
501cefd3cdbSBharat Bhushan     env->gpr[7] = mmubooke_initial_mapsize(env);
502cefd3cdbSBharat Bhushan     env->gpr[8] = 0;
503cefd3cdbSBharat Bhushan     env->gpr[9] = 0;
5043b989d49SAlexander Graf     env->nip = bi->entry;
505cba2026aSAlexander Graf     mmubooke_create_initial_mapping(env);
5063b989d49SAlexander Graf }
5073b989d49SAlexander Graf 
508d85937e6SScott Wood static DeviceState *ppce500_init_mpic_qemu(PPCE500Params *params,
50982fc73b6SScott Wood                                            qemu_irq **irqs)
51082fc73b6SScott Wood {
51182fc73b6SScott Wood     DeviceState *dev;
51282fc73b6SScott Wood     SysBusDevice *s;
51382fc73b6SScott Wood     int i, j, k;
51482fc73b6SScott Wood 
515e1766344SAndreas Färber     dev = qdev_create(NULL, TYPE_OPENPIC);
51682fc73b6SScott Wood     qdev_prop_set_uint32(dev, "model", params->mpic_version);
517d85937e6SScott Wood     qdev_prop_set_uint32(dev, "nb_cpus", smp_cpus);
518d85937e6SScott Wood 
51982fc73b6SScott Wood     qdev_init_nofail(dev);
52082fc73b6SScott Wood     s = SYS_BUS_DEVICE(dev);
52182fc73b6SScott Wood 
52282fc73b6SScott Wood     k = 0;
52382fc73b6SScott Wood     for (i = 0; i < smp_cpus; i++) {
52482fc73b6SScott Wood         for (j = 0; j < OPENPIC_OUTPUT_NB; j++) {
52582fc73b6SScott Wood             sysbus_connect_irq(s, k++, irqs[i][j]);
52682fc73b6SScott Wood         }
52782fc73b6SScott Wood     }
52882fc73b6SScott Wood 
529d85937e6SScott Wood     return dev;
530d85937e6SScott Wood }
531d85937e6SScott Wood 
532d85937e6SScott Wood static DeviceState *ppce500_init_mpic_kvm(PPCE500Params *params,
533d85937e6SScott Wood                                           qemu_irq **irqs)
534d85937e6SScott Wood {
535d85937e6SScott Wood     DeviceState *dev;
536d85937e6SScott Wood     CPUState *cs;
537d85937e6SScott Wood     int r;
538d85937e6SScott Wood 
539dd49c038SAndreas Färber     dev = qdev_create(NULL, TYPE_KVM_OPENPIC);
540d85937e6SScott Wood     qdev_prop_set_uint32(dev, "model", params->mpic_version);
541d85937e6SScott Wood 
542d85937e6SScott Wood     r = qdev_init(dev);
543d85937e6SScott Wood     if (r) {
544d85937e6SScott Wood         return NULL;
545d85937e6SScott Wood     }
546d85937e6SScott Wood 
547bdc44640SAndreas Färber     CPU_FOREACH(cs) {
548d85937e6SScott Wood         if (kvm_openpic_connect_vcpu(dev, cs)) {
549d85937e6SScott Wood             fprintf(stderr, "%s: failed to connect vcpu to irqchip\n",
550d85937e6SScott Wood                     __func__);
551d85937e6SScott Wood             abort();
552d85937e6SScott Wood         }
553d85937e6SScott Wood     }
554d85937e6SScott Wood 
555d85937e6SScott Wood     return dev;
556d85937e6SScott Wood }
557d85937e6SScott Wood 
558d85937e6SScott Wood static qemu_irq *ppce500_init_mpic(PPCE500Params *params, MemoryRegion *ccsr,
559d85937e6SScott Wood                                    qemu_irq **irqs)
560d85937e6SScott Wood {
561d85937e6SScott Wood     qemu_irq *mpic;
562d85937e6SScott Wood     DeviceState *dev = NULL;
563d85937e6SScott Wood     SysBusDevice *s;
564d85937e6SScott Wood     int i;
565d85937e6SScott Wood 
566d85937e6SScott Wood     mpic = g_new(qemu_irq, 256);
567d85937e6SScott Wood 
568d85937e6SScott Wood     if (kvm_enabled()) {
56936ad0e94SMarkus Armbruster         QemuOpts *machine_opts = qemu_get_machine_opts();
57036ad0e94SMarkus Armbruster         bool irqchip_allowed = qemu_opt_get_bool(machine_opts,
571d85937e6SScott Wood                                                 "kernel_irqchip", true);
57236ad0e94SMarkus Armbruster         bool irqchip_required = qemu_opt_get_bool(machine_opts,
573d85937e6SScott Wood                                                   "kernel_irqchip", false);
574d85937e6SScott Wood 
575d85937e6SScott Wood         if (irqchip_allowed) {
576d85937e6SScott Wood             dev = ppce500_init_mpic_kvm(params, irqs);
577d85937e6SScott Wood         }
578d85937e6SScott Wood 
579d85937e6SScott Wood         if (irqchip_required && !dev) {
580d85937e6SScott Wood             fprintf(stderr, "%s: irqchip requested but unavailable\n",
581d85937e6SScott Wood                     __func__);
582d85937e6SScott Wood             abort();
583d85937e6SScott Wood         }
584d85937e6SScott Wood     }
585d85937e6SScott Wood 
586d85937e6SScott Wood     if (!dev) {
587d85937e6SScott Wood         dev = ppce500_init_mpic_qemu(params, irqs);
588d85937e6SScott Wood     }
589d85937e6SScott Wood 
59082fc73b6SScott Wood     for (i = 0; i < 256; i++) {
59182fc73b6SScott Wood         mpic[i] = qdev_get_gpio_in(dev, i);
59282fc73b6SScott Wood     }
59382fc73b6SScott Wood 
594d85937e6SScott Wood     s = SYS_BUS_DEVICE(dev);
59582fc73b6SScott Wood     memory_region_add_subregion(ccsr, MPC8544_MPIC_REGS_OFFSET,
59682fc73b6SScott Wood                                 s->mmio[0].memory);
59782fc73b6SScott Wood 
59882fc73b6SScott Wood     return mpic;
59982fc73b6SScott Wood }
60082fc73b6SScott Wood 
60192238367SMarkus Armbruster void ppce500_init(QEMUMachineInitArgs *args, PPCE500Params *params)
6021db09b84Saurel32 {
60339186d8aSRichard Henderson     MemoryRegion *address_space_mem = get_system_memory();
6042646c133SAvi Kivity     MemoryRegion *ram = g_new(MemoryRegion, 1);
6051db09b84Saurel32     PCIBus *pci_bus;
606e2684c0bSAndreas Färber     CPUPPCState *env = NULL;
6071db09b84Saurel32     uint64_t elf_entry;
6081db09b84Saurel32     uint64_t elf_lowaddr;
609a8170e5eSAvi Kivity     hwaddr entry=0;
610a8170e5eSAvi Kivity     hwaddr loadaddr=UIMAGE_LOAD_BASE;
6111db09b84Saurel32     target_long kernel_size=0;
61275bb6589SLiu Yu     target_ulong dt_base = 0;
61375bb6589SLiu Yu     target_ulong initrd_base = 0;
6141db09b84Saurel32     target_long initrd_size = 0;
615528e536eSAlexander Graf     target_ulong cur_base = 0;
61682fc73b6SScott Wood     int i;
6171db09b84Saurel32     unsigned int pci_irq_nrs[4] = {1, 2, 3, 4};
618a915249fSAlexander Graf     qemu_irq **irqs, *mpic;
619be13cc7aSAlexander Graf     DeviceState *dev;
620e2684c0bSAndreas Färber     CPUPPCState *firstenv = NULL;
6213eddc1beSBharat Bhushan     MemoryRegion *ccsr_addr_space;
622dffb1dc2SBharat Bhushan     SysBusDevice *s;
6233eddc1beSBharat Bhushan     PPCE500CCSRState *ccsr;
6241db09b84Saurel32 
625e61c36d5SAlexander Graf     /* Setup CPUs */
62692238367SMarkus Armbruster     if (args->cpu_model == NULL) {
62792238367SMarkus Armbruster         args->cpu_model = "e500v2_v30";
628ef250db6SAlexander Graf     }
629ef250db6SAlexander Graf 
630a915249fSAlexander Graf     irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *));
631a915249fSAlexander Graf     irqs[0] = g_malloc0(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
632e61c36d5SAlexander Graf     for (i = 0; i < smp_cpus; i++) {
633397b457dSAndreas Färber         PowerPCCPU *cpu;
63455e5c285SAndreas Färber         CPUState *cs;
635e61c36d5SAlexander Graf         qemu_irq *input;
636397b457dSAndreas Färber 
63792238367SMarkus Armbruster         cpu = cpu_ppc_init(args->cpu_model);
638397b457dSAndreas Färber         if (cpu == NULL) {
6391db09b84Saurel32             fprintf(stderr, "Unable to initialize CPU!\n");
6401db09b84Saurel32             exit(1);
6411db09b84Saurel32         }
642397b457dSAndreas Färber         env = &cpu->env;
64355e5c285SAndreas Färber         cs = CPU(cpu);
6441db09b84Saurel32 
645e61c36d5SAlexander Graf         if (!firstenv) {
646e61c36d5SAlexander Graf             firstenv = env;
647e61c36d5SAlexander Graf         }
648e61c36d5SAlexander Graf 
649a915249fSAlexander Graf         irqs[i] = irqs[0] + (i * OPENPIC_OUTPUT_NB);
650a915249fSAlexander Graf         input = (qemu_irq *)env->irq_inputs;
651a915249fSAlexander Graf         irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT];
652a915249fSAlexander Graf         irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT];
65355e5c285SAndreas Färber         env->spr[SPR_BOOKE_PIR] = cs->cpu_index = i;
65468c2dd70SAlexander Graf         env->mpic_iack = MPC8544_CCSRBAR_BASE +
655bd25922eSScott Wood                          MPC8544_MPIC_REGS_OFFSET + 0xa0;
656e61c36d5SAlexander Graf 
657a34a92b9SAndreas Färber         ppc_booke_timers_init(cpu, 400000000, PPC_TIMER_E500);
6583b989d49SAlexander Graf 
6593b989d49SAlexander Graf         /* Register reset handler */
6605c145dacSAlexander Graf         if (!i) {
6615c145dacSAlexander Graf             /* Primary CPU */
6625c145dacSAlexander Graf             struct boot_info *boot_info;
663e61c36d5SAlexander Graf             boot_info = g_malloc0(sizeof(struct boot_info));
664b3305981SScott Wood             qemu_register_reset(ppce500_cpu_reset, cpu);
665e61c36d5SAlexander Graf             env->load_info = boot_info;
6665c145dacSAlexander Graf         } else {
6675c145dacSAlexander Graf             /* Secondary CPUs */
668b3305981SScott Wood             qemu_register_reset(ppce500_cpu_reset_sec, cpu);
6695c145dacSAlexander Graf         }
670e61c36d5SAlexander Graf     }
671e61c36d5SAlexander Graf 
672e61c36d5SAlexander Graf     env = firstenv;
6733b989d49SAlexander Graf 
6741db09b84Saurel32     /* Fixup Memory size on a alignment boundary */
6751db09b84Saurel32     ram_size &= ~(RAM_SIZES_ALIGN - 1);
67692238367SMarkus Armbruster     args->ram_size = ram_size;
6771db09b84Saurel32 
6781db09b84Saurel32     /* Register Memory */
6792c9b15caSPaolo Bonzini     memory_region_init_ram(ram, NULL, "mpc8544ds.ram", ram_size);
680c5705a77SAvi Kivity     vmstate_register_ram_global(ram);
6812646c133SAvi Kivity     memory_region_add_subregion(address_space_mem, 0, ram);
6821db09b84Saurel32 
6833eddc1beSBharat Bhushan     dev = qdev_create(NULL, "e500-ccsr");
6843eddc1beSBharat Bhushan     object_property_add_child(qdev_get_machine(), "e500-ccsr",
6853eddc1beSBharat Bhushan                               OBJECT(dev), NULL);
6863eddc1beSBharat Bhushan     qdev_init_nofail(dev);
6873eddc1beSBharat Bhushan     ccsr = CCSR(dev);
6883eddc1beSBharat Bhushan     ccsr_addr_space = &ccsr->ccsr_space;
6893eddc1beSBharat Bhushan     memory_region_add_subregion(address_space_mem, MPC8544_CCSRBAR_BASE,
6903eddc1beSBharat Bhushan                                 ccsr_addr_space);
691dffb1dc2SBharat Bhushan 
69282fc73b6SScott Wood     mpic = ppce500_init_mpic(params, ccsr_addr_space, irqs);
6931db09b84Saurel32 
6941db09b84Saurel32     /* Serial */
6952d48377aSBlue Swirl     if (serial_hds[0]) {
6963eddc1beSBharat Bhushan         serial_mm_init(ccsr_addr_space, MPC8544_SERIAL0_REGS_OFFSET,
697cdbb912aSAlexander Graf                        0, mpic[42], 399193,
6982ff0c7c3SRichard Henderson                        serial_hds[0], DEVICE_BIG_ENDIAN);
6992d48377aSBlue Swirl     }
7001db09b84Saurel32 
7012d48377aSBlue Swirl     if (serial_hds[1]) {
7023eddc1beSBharat Bhushan         serial_mm_init(ccsr_addr_space, MPC8544_SERIAL1_REGS_OFFSET,
703cdbb912aSAlexander Graf                        0, mpic[42], 399193,
70459de4f98SBharat Bhushan                        serial_hds[1], DEVICE_BIG_ENDIAN);
7052d48377aSBlue Swirl     }
7061db09b84Saurel32 
707b0fb8423SAlexander Graf     /* General Utility device */
708dffb1dc2SBharat Bhushan     dev = qdev_create(NULL, "mpc8544-guts");
709dffb1dc2SBharat Bhushan     qdev_init_nofail(dev);
710dffb1dc2SBharat Bhushan     s = SYS_BUS_DEVICE(dev);
7113eddc1beSBharat Bhushan     memory_region_add_subregion(ccsr_addr_space, MPC8544_UTIL_OFFSET,
712dffb1dc2SBharat Bhushan                                 sysbus_mmio_get_region(s, 0));
713b0fb8423SAlexander Graf 
7141db09b84Saurel32     /* PCI */
715dffb1dc2SBharat Bhushan     dev = qdev_create(NULL, "e500-pcihost");
716492ec48dSAlexander Graf     qdev_prop_set_uint32(dev, "first_slot", params->pci_first_slot);
717dffb1dc2SBharat Bhushan     qdev_init_nofail(dev);
718dffb1dc2SBharat Bhushan     s = SYS_BUS_DEVICE(dev);
719dffb1dc2SBharat Bhushan     sysbus_connect_irq(s, 0, mpic[pci_irq_nrs[0]]);
720dffb1dc2SBharat Bhushan     sysbus_connect_irq(s, 1, mpic[pci_irq_nrs[1]]);
721dffb1dc2SBharat Bhushan     sysbus_connect_irq(s, 2, mpic[pci_irq_nrs[2]]);
722dffb1dc2SBharat Bhushan     sysbus_connect_irq(s, 3, mpic[pci_irq_nrs[3]]);
7233eddc1beSBharat Bhushan     memory_region_add_subregion(ccsr_addr_space, MPC8544_PCI_REGS_OFFSET,
724dffb1dc2SBharat Bhushan                                 sysbus_mmio_get_region(s, 0));
725dffb1dc2SBharat Bhushan 
726d461e3b9SAlexander Graf     pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
7271db09b84Saurel32     if (!pci_bus)
7281db09b84Saurel32         printf("couldn't create PCI controller!\n");
7291db09b84Saurel32 
7301356b98dSAndreas Färber     sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, MPC8544_PCI_IO);
7311db09b84Saurel32 
7321db09b84Saurel32     if (pci_bus) {
7331db09b84Saurel32         /* Register network interfaces. */
7341db09b84Saurel32         for (i = 0; i < nb_nics; i++) {
73529b358f9SDavid Gibson             pci_nic_init_nofail(&nd_table[i], pci_bus, "virtio", NULL);
7361db09b84Saurel32         }
7371db09b84Saurel32     }
7381db09b84Saurel32 
7395c145dacSAlexander Graf     /* Register spinning region */
7405c145dacSAlexander Graf     sysbus_create_simple("e500-spin", MPC8544_SPIN_BASE, NULL);
7415c145dacSAlexander Graf 
7421db09b84Saurel32     /* Load kernel. */
74392238367SMarkus Armbruster     if (args->kernel_filename) {
74492238367SMarkus Armbruster         kernel_size = load_uimage(args->kernel_filename, &entry,
745e6eaabebSScott Wood                                   &loadaddr, NULL);
7461db09b84Saurel32         if (kernel_size < 0) {
74792238367SMarkus Armbruster             kernel_size = load_elf(args->kernel_filename, NULL, NULL,
748e6eaabebSScott Wood                                    &elf_entry, &elf_lowaddr, NULL, 1,
749e6eaabebSScott Wood                                    ELF_MACHINE, 0);
7501db09b84Saurel32             entry = elf_entry;
7511db09b84Saurel32             loadaddr = elf_lowaddr;
7521db09b84Saurel32         }
7531db09b84Saurel32         /* XXX try again as binary */
7541db09b84Saurel32         if (kernel_size < 0) {
7551db09b84Saurel32             fprintf(stderr, "qemu: could not load kernel '%s'\n",
75692238367SMarkus Armbruster                     args->kernel_filename);
7571db09b84Saurel32             exit(1);
7581db09b84Saurel32         }
759528e536eSAlexander Graf 
760528e536eSAlexander Graf         cur_base = loadaddr + kernel_size;
761b8dec144SAlexander Graf 
762b8dec144SAlexander Graf         /* Reserve space for dtb */
763b8dec144SAlexander Graf         dt_base = (cur_base + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
764b8dec144SAlexander Graf         cur_base += DTB_MAX_SIZE;
7651db09b84Saurel32     }
7661db09b84Saurel32 
7671db09b84Saurel32     /* Load initrd. */
76892238367SMarkus Armbruster     if (args->initrd_filename) {
769528e536eSAlexander Graf         initrd_base = (cur_base + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK;
77092238367SMarkus Armbruster         initrd_size = load_image_targphys(args->initrd_filename, initrd_base,
771d7585251Spbrook                                           ram_size - initrd_base);
7721db09b84Saurel32 
7731db09b84Saurel32         if (initrd_size < 0) {
7741db09b84Saurel32             fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
77592238367SMarkus Armbruster                     args->initrd_filename);
7761db09b84Saurel32             exit(1);
7771db09b84Saurel32         }
778528e536eSAlexander Graf 
779528e536eSAlexander Graf         cur_base = initrd_base + initrd_size;
7801db09b84Saurel32     }
7811db09b84Saurel32 
7821db09b84Saurel32     /* If we're loading a kernel directly, we must load the device tree too. */
78392238367SMarkus Armbruster     if (args->kernel_filename) {
7845c145dacSAlexander Graf         struct boot_info *boot_info;
785cba2026aSAlexander Graf         int dt_size;
7865c145dacSAlexander Graf 
78728290f37SAlexander Graf         dt_size = ppce500_prep_device_tree(args, params, dt_base,
78892238367SMarkus Armbruster                                            initrd_base, initrd_size);
789cba2026aSAlexander Graf         if (dt_size < 0) {
7901db09b84Saurel32             fprintf(stderr, "couldn't load device tree\n");
7911db09b84Saurel32             exit(1);
7921db09b84Saurel32         }
793b8dec144SAlexander Graf         assert(dt_size < DTB_MAX_SIZE);
7941db09b84Saurel32 
795e61c36d5SAlexander Graf         boot_info = env->load_info;
7963b989d49SAlexander Graf         boot_info->entry = entry;
7973b989d49SAlexander Graf         boot_info->dt_base = dt_base;
798cba2026aSAlexander Graf         boot_info->dt_size = dt_size;
7991db09b84Saurel32     }
8001db09b84Saurel32 
8013b989d49SAlexander Graf     if (kvm_enabled()) {
8021db09b84Saurel32         kvmppc_init();
8033b989d49SAlexander Graf     }
8041db09b84Saurel32 }
8053eddc1beSBharat Bhushan 
8063eddc1beSBharat Bhushan static int e500_ccsr_initfn(SysBusDevice *dev)
8073eddc1beSBharat Bhushan {
8083eddc1beSBharat Bhushan     PPCE500CCSRState *ccsr;
8093eddc1beSBharat Bhushan 
8103eddc1beSBharat Bhushan     ccsr = CCSR(dev);
81140c5dce9SPaolo Bonzini     memory_region_init(&ccsr->ccsr_space, OBJECT(ccsr), "e500-ccsr",
8123eddc1beSBharat Bhushan                        MPC8544_CCSRBAR_SIZE);
8133eddc1beSBharat Bhushan     return 0;
8143eddc1beSBharat Bhushan }
8153eddc1beSBharat Bhushan 
8163eddc1beSBharat Bhushan static void e500_ccsr_class_init(ObjectClass *klass, void *data)
8173eddc1beSBharat Bhushan {
8183eddc1beSBharat Bhushan     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
8193eddc1beSBharat Bhushan     k->init = e500_ccsr_initfn;
8203eddc1beSBharat Bhushan }
8213eddc1beSBharat Bhushan 
8223eddc1beSBharat Bhushan static const TypeInfo e500_ccsr_info = {
8233eddc1beSBharat Bhushan     .name          = TYPE_CCSR,
8243eddc1beSBharat Bhushan     .parent        = TYPE_SYS_BUS_DEVICE,
8253eddc1beSBharat Bhushan     .instance_size = sizeof(PPCE500CCSRState),
8263eddc1beSBharat Bhushan     .class_init    = e500_ccsr_class_init,
8273eddc1beSBharat Bhushan };
8283eddc1beSBharat Bhushan 
8293eddc1beSBharat Bhushan static void e500_register_types(void)
8303eddc1beSBharat Bhushan {
8313eddc1beSBharat Bhushan     type_register_static(&e500_ccsr_info);
8323eddc1beSBharat Bhushan }
8333eddc1beSBharat Bhushan 
8343eddc1beSBharat Bhushan type_init(e500_register_types)
835