xref: /qemu/hw/ppc/e500.c (revision 7e99826c350f21cb7d162e802efaa5d1b8689ad0)
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"
201db09b84Saurel32 #include "net.h"
214a18e7c9SScott Wood #include "hw/hw.h"
224a18e7c9SScott Wood #include "hw/pc.h"
234a18e7c9SScott Wood #include "hw/pci.h"
244a18e7c9SScott Wood #include "hw/boards.h"
251db09b84Saurel32 #include "sysemu.h"
261db09b84Saurel32 #include "kvm.h"
271db09b84Saurel32 #include "kvm_ppc.h"
281db09b84Saurel32 #include "device_tree.h"
294a18e7c9SScott Wood #include "hw/openpic.h"
304a18e7c9SScott Wood #include "hw/ppc.h"
314a18e7c9SScott Wood #include "hw/loader.h"
32ca20cf32SBlue Swirl #include "elf.h"
334a18e7c9SScott Wood #include "hw/sysbus.h"
3439186d8aSRichard Henderson #include "exec-memory.h"
35cba2026aSAlexander Graf #include "host-utils.h"
361db09b84Saurel32 
371db09b84Saurel32 #define BINARY_DEVICE_TREE_FILE    "mpc8544ds.dtb"
381db09b84Saurel32 #define UIMAGE_LOAD_BASE           0
3975bb6589SLiu Yu #define DTC_LOAD_PAD               0x500000
4075bb6589SLiu Yu #define DTC_PAD_MASK               0xFFFFF
4175bb6589SLiu Yu #define INITRD_LOAD_PAD            0x2000000
4275bb6589SLiu Yu #define INITRD_PAD_MASK            0xFFFFFF
431db09b84Saurel32 
441db09b84Saurel32 #define RAM_SIZES_ALIGN            (64UL << 20)
451db09b84Saurel32 
46b3305981SScott Wood /* TODO: parameterize */
47ed2bc496SAlexander Graf #define MPC8544_CCSRBAR_BASE       0xE0000000ULL
48ed2bc496SAlexander Graf #define MPC8544_CCSRBAR_SIZE       0x00100000ULL
49ed2bc496SAlexander Graf #define MPC8544_MPIC_REGS_BASE     (MPC8544_CCSRBAR_BASE + 0x40000ULL)
50ed2bc496SAlexander Graf #define MPC8544_SERIAL0_REGS_BASE  (MPC8544_CCSRBAR_BASE + 0x4500ULL)
51ed2bc496SAlexander Graf #define MPC8544_SERIAL1_REGS_BASE  (MPC8544_CCSRBAR_BASE + 0x4600ULL)
52ed2bc496SAlexander Graf #define MPC8544_PCI_REGS_BASE      (MPC8544_CCSRBAR_BASE + 0x8000ULL)
53ed2bc496SAlexander Graf #define MPC8544_PCI_REGS_SIZE      0x1000ULL
54ed2bc496SAlexander Graf #define MPC8544_PCI_IO             0xE1000000ULL
55ed2bc496SAlexander Graf #define MPC8544_PCI_IOLEN          0x10000ULL
56ed2bc496SAlexander Graf #define MPC8544_UTIL_BASE          (MPC8544_CCSRBAR_BASE + 0xe0000ULL)
57ed2bc496SAlexander Graf #define MPC8544_SPIN_BASE          0xEF000000ULL
581db09b84Saurel32 
593b989d49SAlexander Graf struct boot_info
603b989d49SAlexander Graf {
613b989d49SAlexander Graf     uint32_t dt_base;
62cba2026aSAlexander Graf     uint32_t dt_size;
633b989d49SAlexander Graf     uint32_t entry;
643b989d49SAlexander Graf };
653b989d49SAlexander Graf 
660dbc0798SAlexander Graf static void pci_map_create(void *fdt, uint32_t *pci_map, uint32_t mpic)
670dbc0798SAlexander Graf {
680dbc0798SAlexander Graf     int i;
690dbc0798SAlexander Graf     const uint32_t tmp[] = {
700dbc0798SAlexander Graf                              /* IDSEL 0x11 J17 Slot 1 */
71*7e99826cSAlexander Graf                              0x8800, 0x0, 0x0, 0x1, mpic, 0x2, 0x1,
72*7e99826cSAlexander Graf                              0x8800, 0x0, 0x0, 0x2, mpic, 0x3, 0x1,
73*7e99826cSAlexander Graf                              0x8800, 0x0, 0x0, 0x3, mpic, 0x4, 0x1,
74*7e99826cSAlexander Graf                              0x8800, 0x0, 0x0, 0x4, mpic, 0x1, 0x1,
750dbc0798SAlexander Graf 
760dbc0798SAlexander Graf                              /* IDSEL 0x12 J16 Slot 2 */
77*7e99826cSAlexander Graf                              0x9000, 0x0, 0x0, 0x1, mpic, 0x3, 0x1,
78*7e99826cSAlexander Graf                              0x9000, 0x0, 0x0, 0x2, mpic, 0x4, 0x1,
79*7e99826cSAlexander Graf                              0x9000, 0x0, 0x0, 0x3, mpic, 0x2, 0x1,
80*7e99826cSAlexander Graf                              0x9000, 0x0, 0x0, 0x4, mpic, 0x1, 0x1,
810dbc0798SAlexander Graf                            };
82*7e99826cSAlexander Graf     for (i = 0; i < (7 * 8); i++) {
830dbc0798SAlexander Graf         pci_map[i] = cpu_to_be32(tmp[i]);
840dbc0798SAlexander Graf     }
850dbc0798SAlexander Graf }
860dbc0798SAlexander Graf 
87a053a7ceSAlexander Graf static void dt_serial_create(void *fdt, unsigned long long offset,
88a053a7ceSAlexander Graf                              const char *soc, const char *mpic,
89a053a7ceSAlexander Graf                              const char *alias, int idx, bool defcon)
90a053a7ceSAlexander Graf {
91a053a7ceSAlexander Graf     char ser[128];
92a053a7ceSAlexander Graf 
93a053a7ceSAlexander Graf     snprintf(ser, sizeof(ser), "%s/serial@%llx", soc, offset);
94a053a7ceSAlexander Graf     qemu_devtree_add_subnode(fdt, ser);
95a053a7ceSAlexander Graf     qemu_devtree_setprop_string(fdt, ser, "device_type", "serial");
96a053a7ceSAlexander Graf     qemu_devtree_setprop_string(fdt, ser, "compatible", "ns16550");
97a053a7ceSAlexander Graf     qemu_devtree_setprop_cells(fdt, ser, "reg", offset, 0x100);
98a053a7ceSAlexander Graf     qemu_devtree_setprop_cell(fdt, ser, "cell-index", idx);
99a053a7ceSAlexander Graf     qemu_devtree_setprop_cell(fdt, ser, "clock-frequency", 0);
100*7e99826cSAlexander Graf     qemu_devtree_setprop_cells(fdt, ser, "interrupts", 42, 2);
101a053a7ceSAlexander Graf     qemu_devtree_setprop_phandle(fdt, ser, "interrupt-parent", mpic);
102a053a7ceSAlexander Graf     qemu_devtree_setprop_string(fdt, "/aliases", alias, ser);
103a053a7ceSAlexander Graf 
104a053a7ceSAlexander Graf     if (defcon) {
105a053a7ceSAlexander Graf         qemu_devtree_setprop_string(fdt, "/chosen", "linux,stdout-path", ser);
106a053a7ceSAlexander Graf     }
107a053a7ceSAlexander Graf }
108a053a7ceSAlexander Graf 
109b3305981SScott Wood static int ppce500_load_device_tree(CPUPPCState *env,
110e6eaabebSScott Wood                                     PPCE500Params *params,
1115de6b46dSAlexander Graf                                     target_phys_addr_t addr,
112c227f099SAnthony Liguori                                     target_phys_addr_t initrd_base,
113e6eaabebSScott Wood                                     target_phys_addr_t initrd_size)
1141db09b84Saurel32 {
115dbf916d8SAurelien Jarno     int ret = -1;
116e6eaabebSScott Wood     uint64_t mem_reg_property[] = { 0, cpu_to_be64(params->ram_size) };
1177ec632b4Spbrook     int fdt_size;
118dbf916d8SAurelien Jarno     void *fdt;
1195de6b46dSAlexander Graf     uint8_t hypercall[16];
120911d6e7aSAlexander Graf     uint32_t clock_freq = 400000000;
121911d6e7aSAlexander Graf     uint32_t tb_freq = 400000000;
122621d05e3SAlexander Graf     int i;
123e6eaabebSScott Wood     const char *toplevel_compat = NULL; /* user override */
124ebb9518aSAlexander Graf     char compatible_sb[] = "fsl,mpc8544-immr\0simple-bus";
1255da96624SAlexander Graf     char soc[128];
12619ac9deaSAlexander Graf     char mpic[128];
12719ac9deaSAlexander Graf     uint32_t mpic_ph;
128f5038483SAlexander Graf     char gutil[128];
1290dbc0798SAlexander Graf     char pci[128];
130*7e99826cSAlexander Graf     uint32_t pci_map[7 * 8];
1313627757eSAlexander Graf     uint32_t pci_ranges[14] =
1323627757eSAlexander Graf         {
1333627757eSAlexander Graf             0x2000000, 0x0, 0xc0000000,
1343627757eSAlexander Graf             0x0, 0xc0000000,
1353627757eSAlexander Graf             0x0, 0x20000000,
1363627757eSAlexander Graf 
1373627757eSAlexander Graf             0x1000000, 0x0, 0x0,
1383627757eSAlexander Graf             0x0, 0xe1000000,
1393627757eSAlexander Graf             0x0, 0x10000,
1403627757eSAlexander Graf         };
14125b42708SAlexander Graf     QemuOpts *machine_opts;
14225b42708SAlexander Graf     const char *dumpdtb = NULL;
143d1b93565SAlexander Graf     const char *dtb_file = NULL;
144d1b93565SAlexander Graf 
145d1b93565SAlexander Graf     machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0);
146d1b93565SAlexander Graf     if (machine_opts) {
147d1b93565SAlexander Graf         dumpdtb = qemu_opt_get(machine_opts, "dumpdtb");
148d1b93565SAlexander Graf         dtb_file = qemu_opt_get(machine_opts, "dtb");
149e6eaabebSScott Wood         toplevel_compat = qemu_opt_get(machine_opts, "dt_compatible");
150d1b93565SAlexander Graf     }
151d1b93565SAlexander Graf 
152d1b93565SAlexander Graf     if (dtb_file) {
153d1b93565SAlexander Graf         char *filename;
154d1b93565SAlexander Graf         filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_file);
155d1b93565SAlexander Graf         if (!filename) {
156d1b93565SAlexander Graf             goto out;
157d1b93565SAlexander Graf         }
158d1b93565SAlexander Graf 
159d1b93565SAlexander Graf         fdt = load_device_tree(filename, &fdt_size);
160d1b93565SAlexander Graf         if (!fdt) {
161d1b93565SAlexander Graf             goto out;
162d1b93565SAlexander Graf         }
163d1b93565SAlexander Graf         goto done;
164d1b93565SAlexander Graf     }
1651db09b84Saurel32 
1662636fcb6SAlexander Graf     fdt = create_device_tree(&fdt_size);
1675cea8590SPaul Brook     if (fdt == NULL) {
1685cea8590SPaul Brook         goto out;
1695cea8590SPaul Brook     }
1701db09b84Saurel32 
1711db09b84Saurel32     /* Manipulate device tree in memory. */
1723627757eSAlexander Graf     qemu_devtree_setprop_cell(fdt, "/", "#address-cells", 2);
1733627757eSAlexander Graf     qemu_devtree_setprop_cell(fdt, "/", "#size-cells", 2);
17451b852b7SAlexander Graf 
175dd0bcfcaSAlexander Graf     qemu_devtree_add_subnode(fdt, "/memory");
176dd0bcfcaSAlexander Graf     qemu_devtree_setprop_string(fdt, "/memory", "device_type", "memory");
177dd0bcfcaSAlexander Graf     qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property,
1781db09b84Saurel32                          sizeof(mem_reg_property));
1791db09b84Saurel32 
180f5231aafSAlexander Graf     qemu_devtree_add_subnode(fdt, "/chosen");
1813b989d49SAlexander Graf     if (initrd_size) {
1821db09b84Saurel32         ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start",
1831db09b84Saurel32                                         initrd_base);
1843b989d49SAlexander Graf         if (ret < 0) {
1851db09b84Saurel32             fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
1863b989d49SAlexander Graf         }
1871db09b84Saurel32 
1881db09b84Saurel32         ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end",
1891db09b84Saurel32                                         (initrd_base + initrd_size));
1903b989d49SAlexander Graf         if (ret < 0) {
1911db09b84Saurel32             fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
1923b989d49SAlexander Graf         }
1933b989d49SAlexander Graf     }
1941db09b84Saurel32 
1951db09b84Saurel32     ret = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs",
196e6eaabebSScott Wood                                       params->kernel_cmdline);
1971db09b84Saurel32     if (ret < 0)
1981db09b84Saurel32         fprintf(stderr, "couldn't set /chosen/bootargs\n");
1991db09b84Saurel32 
2001db09b84Saurel32     if (kvm_enabled()) {
201911d6e7aSAlexander Graf         /* Read out host's frequencies */
202911d6e7aSAlexander Graf         clock_freq = kvmppc_get_clockfreq();
203911d6e7aSAlexander Graf         tb_freq = kvmppc_get_tbfreq();
2045de6b46dSAlexander Graf 
2055de6b46dSAlexander Graf         /* indicate KVM hypercall interface */
206d50f71a5SAlexander Graf         qemu_devtree_add_subnode(fdt, "/hypervisor");
2075de6b46dSAlexander Graf         qemu_devtree_setprop_string(fdt, "/hypervisor", "compatible",
2085de6b46dSAlexander Graf                                     "linux,kvm");
2095de6b46dSAlexander Graf         kvmppc_get_hypercall(env, hypercall, sizeof(hypercall));
2105de6b46dSAlexander Graf         qemu_devtree_setprop(fdt, "/hypervisor", "hcall-instructions",
2115de6b46dSAlexander Graf                              hypercall, sizeof(hypercall));
2121db09b84Saurel32     }
2131db09b84Saurel32 
214625e665bSAlexander Graf     /* Create CPU nodes */
215625e665bSAlexander Graf     qemu_devtree_add_subnode(fdt, "/cpus");
216625e665bSAlexander Graf     qemu_devtree_setprop_cell(fdt, "/cpus", "#address-cells", 1);
217625e665bSAlexander Graf     qemu_devtree_setprop_cell(fdt, "/cpus", "#size-cells", 0);
218625e665bSAlexander Graf 
2191e3debf0SAlexander Graf     /* We need to generate the cpu nodes in reverse order, so Linux can pick
2201e3debf0SAlexander Graf        the first node as boot node and be happy */
2211e3debf0SAlexander Graf     for (i = smp_cpus - 1; i >= 0; i--) {
222621d05e3SAlexander Graf         char cpu_name[128];
2231d2e5c52SAlexander Graf         uint64_t cpu_release_addr = MPC8544_SPIN_BASE + (i * 0x20);
22410f25a46SAlexander Graf 
2251e3debf0SAlexander Graf         for (env = first_cpu; env != NULL; env = env->next_cpu) {
2261e3debf0SAlexander Graf             if (env->cpu_index == i) {
2271e3debf0SAlexander Graf                 break;
2281e3debf0SAlexander Graf             }
229621d05e3SAlexander Graf         }
230911d6e7aSAlexander Graf 
2311e3debf0SAlexander Graf         if (!env) {
2321e3debf0SAlexander Graf             continue;
2331e3debf0SAlexander Graf         }
2341e3debf0SAlexander Graf 
2351e3debf0SAlexander Graf         snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x", env->cpu_index);
2361e3debf0SAlexander Graf         qemu_devtree_add_subnode(fdt, cpu_name);
2371e3debf0SAlexander Graf         qemu_devtree_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq);
2381e3debf0SAlexander Graf         qemu_devtree_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq);
2391e3debf0SAlexander Graf         qemu_devtree_setprop_string(fdt, cpu_name, "device_type", "cpu");
2401e3debf0SAlexander Graf         qemu_devtree_setprop_cell(fdt, cpu_name, "reg", env->cpu_index);
2411e3debf0SAlexander Graf         qemu_devtree_setprop_cell(fdt, cpu_name, "d-cache-line-size",
2421e3debf0SAlexander Graf                                   env->dcache_line_size);
2431e3debf0SAlexander Graf         qemu_devtree_setprop_cell(fdt, cpu_name, "i-cache-line-size",
2441e3debf0SAlexander Graf                                   env->icache_line_size);
2451e3debf0SAlexander Graf         qemu_devtree_setprop_cell(fdt, cpu_name, "d-cache-size", 0x8000);
2461e3debf0SAlexander Graf         qemu_devtree_setprop_cell(fdt, cpu_name, "i-cache-size", 0x8000);
2471e3debf0SAlexander Graf         qemu_devtree_setprop_cell(fdt, cpu_name, "bus-frequency", 0);
2481e3debf0SAlexander Graf         if (env->cpu_index) {
2491e3debf0SAlexander Graf             qemu_devtree_setprop_string(fdt, cpu_name, "status", "disabled");
2501e3debf0SAlexander Graf             qemu_devtree_setprop_string(fdt, cpu_name, "enable-method", "spin-table");
2511d2e5c52SAlexander Graf             qemu_devtree_setprop_u64(fdt, cpu_name, "cpu-release-addr",
2521d2e5c52SAlexander Graf                                      cpu_release_addr);
2531e3debf0SAlexander Graf         } else {
2541e3debf0SAlexander Graf             qemu_devtree_setprop_string(fdt, cpu_name, "status", "okay");
2551e3debf0SAlexander Graf         }
2561db09b84Saurel32     }
2571db09b84Saurel32 
2580cfc6e8dSAlexander Graf     qemu_devtree_add_subnode(fdt, "/aliases");
2595da96624SAlexander Graf     /* XXX These should go into their respective devices' code */
260ed2bc496SAlexander Graf     snprintf(soc, sizeof(soc), "/soc@%llx", MPC8544_CCSRBAR_BASE);
2615da96624SAlexander Graf     qemu_devtree_add_subnode(fdt, soc);
2625da96624SAlexander Graf     qemu_devtree_setprop_string(fdt, soc, "device_type", "soc");
263ebb9518aSAlexander Graf     qemu_devtree_setprop(fdt, soc, "compatible", compatible_sb,
264ebb9518aSAlexander Graf                          sizeof(compatible_sb));
2655da96624SAlexander Graf     qemu_devtree_setprop_cell(fdt, soc, "#address-cells", 1);
2665da96624SAlexander Graf     qemu_devtree_setprop_cell(fdt, soc, "#size-cells", 1);
2673627757eSAlexander Graf     qemu_devtree_setprop_cells(fdt, soc, "ranges", 0x0,
2683627757eSAlexander Graf                                MPC8544_CCSRBAR_BASE >> 32, MPC8544_CCSRBAR_BASE,
2695da96624SAlexander Graf                                MPC8544_CCSRBAR_SIZE);
2705da96624SAlexander Graf     /* XXX should contain a reasonable value */
2715da96624SAlexander Graf     qemu_devtree_setprop_cell(fdt, soc, "bus-frequency", 0);
2725da96624SAlexander Graf 
273ed2bc496SAlexander Graf     snprintf(mpic, sizeof(mpic), "%s/pic@%llx", soc,
27419ac9deaSAlexander Graf              MPC8544_MPIC_REGS_BASE - MPC8544_CCSRBAR_BASE);
27519ac9deaSAlexander Graf     qemu_devtree_add_subnode(fdt, mpic);
27619ac9deaSAlexander Graf     qemu_devtree_setprop_string(fdt, mpic, "device_type", "open-pic");
277*7e99826cSAlexander Graf     qemu_devtree_setprop_string(fdt, mpic, "compatible", "chrp,open-pic");
27819ac9deaSAlexander Graf     qemu_devtree_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_BASE -
27919ac9deaSAlexander Graf                                MPC8544_CCSRBAR_BASE, 0x40000);
28019ac9deaSAlexander Graf     qemu_devtree_setprop_cell(fdt, mpic, "#address-cells", 0);
281*7e99826cSAlexander Graf     qemu_devtree_setprop_cell(fdt, mpic, "#interrupt-cells", 2);
28219ac9deaSAlexander Graf     mpic_ph = qemu_devtree_alloc_phandle(fdt);
28319ac9deaSAlexander Graf     qemu_devtree_setprop_cell(fdt, mpic, "phandle", mpic_ph);
28419ac9deaSAlexander Graf     qemu_devtree_setprop_cell(fdt, mpic, "linux,phandle", mpic_ph);
28519ac9deaSAlexander Graf     qemu_devtree_setprop(fdt, mpic, "interrupt-controller", NULL, 0);
28619ac9deaSAlexander Graf 
2870cfc6e8dSAlexander Graf     /*
2880cfc6e8dSAlexander Graf      * We have to generate ser1 first, because Linux takes the first
2890cfc6e8dSAlexander Graf      * device it finds in the dt as serial output device. And we generate
2900cfc6e8dSAlexander Graf      * devices in reverse order to the dt.
2910cfc6e8dSAlexander Graf      */
292a053a7ceSAlexander Graf     dt_serial_create(fdt, MPC8544_SERIAL1_REGS_BASE - MPC8544_CCSRBAR_BASE,
293a053a7ceSAlexander Graf                      soc, mpic, "serial1", 1, false);
294a053a7ceSAlexander Graf     dt_serial_create(fdt, MPC8544_SERIAL0_REGS_BASE - MPC8544_CCSRBAR_BASE,
295a053a7ceSAlexander Graf                      soc, mpic, "serial0", 0, true);
2960cfc6e8dSAlexander Graf 
297ed2bc496SAlexander Graf     snprintf(gutil, sizeof(gutil), "%s/global-utilities@%llx", soc,
298f5038483SAlexander Graf              MPC8544_UTIL_BASE - MPC8544_CCSRBAR_BASE);
299f5038483SAlexander Graf     qemu_devtree_add_subnode(fdt, gutil);
300f5038483SAlexander Graf     qemu_devtree_setprop_string(fdt, gutil, "compatible", "fsl,mpc8544-guts");
301f5038483SAlexander Graf     qemu_devtree_setprop_cells(fdt, gutil, "reg", MPC8544_UTIL_BASE -
302f5038483SAlexander Graf                                MPC8544_CCSRBAR_BASE, 0x1000);
303f5038483SAlexander Graf     qemu_devtree_setprop(fdt, gutil, "fsl,has-rstcr", NULL, 0);
304f5038483SAlexander Graf 
305ed2bc496SAlexander Graf     snprintf(pci, sizeof(pci), "/pci@%llx", MPC8544_PCI_REGS_BASE);
3060dbc0798SAlexander Graf     qemu_devtree_add_subnode(fdt, pci);
3070dbc0798SAlexander Graf     qemu_devtree_setprop_cell(fdt, pci, "cell-index", 0);
3080dbc0798SAlexander Graf     qemu_devtree_setprop_string(fdt, pci, "compatible", "fsl,mpc8540-pci");
3090dbc0798SAlexander Graf     qemu_devtree_setprop_string(fdt, pci, "device_type", "pci");
3100dbc0798SAlexander Graf     qemu_devtree_setprop_cells(fdt, pci, "interrupt-map-mask", 0xf800, 0x0,
3110dbc0798SAlexander Graf                                0x0, 0x7);
3120dbc0798SAlexander Graf     pci_map_create(fdt, pci_map, qemu_devtree_get_phandle(fdt, mpic));
3130dbc0798SAlexander Graf     qemu_devtree_setprop(fdt, pci, "interrupt-map", pci_map, sizeof(pci_map));
3140dbc0798SAlexander Graf     qemu_devtree_setprop_phandle(fdt, pci, "interrupt-parent", mpic);
315*7e99826cSAlexander Graf     qemu_devtree_setprop_cells(fdt, pci, "interrupts", 24, 2);
3160dbc0798SAlexander Graf     qemu_devtree_setprop_cells(fdt, pci, "bus-range", 0, 255);
3173627757eSAlexander Graf     for (i = 0; i < 14; i++) {
3180dbc0798SAlexander Graf         pci_ranges[i] = cpu_to_be32(pci_ranges[i]);
3190dbc0798SAlexander Graf     }
3200dbc0798SAlexander Graf     qemu_devtree_setprop(fdt, pci, "ranges", pci_ranges, sizeof(pci_ranges));
3213627757eSAlexander Graf     qemu_devtree_setprop_cells(fdt, pci, "reg", MPC8544_PCI_REGS_BASE >> 32,
3223627757eSAlexander Graf                                MPC8544_PCI_REGS_BASE, 0, 0x1000);
3230dbc0798SAlexander Graf     qemu_devtree_setprop_cell(fdt, pci, "clock-frequency", 66666666);
3240dbc0798SAlexander Graf     qemu_devtree_setprop_cell(fdt, pci, "#interrupt-cells", 1);
3250dbc0798SAlexander Graf     qemu_devtree_setprop_cell(fdt, pci, "#size-cells", 2);
3260dbc0798SAlexander Graf     qemu_devtree_setprop_cell(fdt, pci, "#address-cells", 3);
3270dbc0798SAlexander Graf     qemu_devtree_setprop_string(fdt, "/aliases", "pci0", pci);
3280dbc0798SAlexander Graf 
329e6eaabebSScott Wood     params->fixup_devtree(params, fdt);
330e6eaabebSScott Wood 
331e6eaabebSScott Wood     if (toplevel_compat) {
332e6eaabebSScott Wood         qemu_devtree_setprop(fdt, "/", "compatible", toplevel_compat,
333e6eaabebSScott Wood                              strlen(toplevel_compat) + 1);
334e6eaabebSScott Wood     }
335e6eaabebSScott Wood 
336d1b93565SAlexander Graf done:
33725b42708SAlexander Graf     if (dumpdtb) {
33825b42708SAlexander Graf         /* Dump the dtb to a file and quit */
33925b42708SAlexander Graf         FILE *f = fopen(dumpdtb, "wb");
34025b42708SAlexander Graf         size_t len;
34125b42708SAlexander Graf         len = fwrite(fdt, fdt_size, 1, f);
34225b42708SAlexander Graf         fclose(f);
34325b42708SAlexander Graf         if (len != fdt_size) {
34425b42708SAlexander Graf             exit(1);
34525b42708SAlexander Graf         }
34625b42708SAlexander Graf         exit(0);
34725b42708SAlexander Graf     }
34825b42708SAlexander Graf 
34904088adbSLiu Yu     ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
350cba2026aSAlexander Graf     if (ret < 0) {
351cba2026aSAlexander Graf         goto out;
352cba2026aSAlexander Graf     }
3537267c094SAnthony Liguori     g_free(fdt);
354cba2026aSAlexander Graf     ret = fdt_size;
3557ec632b4Spbrook 
3561db09b84Saurel32 out:
3571db09b84Saurel32 
35804088adbSLiu Yu     return ret;
3591db09b84Saurel32 }
3601db09b84Saurel32 
361cba2026aSAlexander Graf /* Create -kernel TLB entries for BookE.  */
362d1e256feSAlexander Graf static inline target_phys_addr_t booke206_page_size_to_tlb(uint64_t size)
363d1e256feSAlexander Graf {
364cba2026aSAlexander Graf     return 63 - clz64(size >> 10);
365d1e256feSAlexander Graf }
366d1e256feSAlexander Graf 
367cba2026aSAlexander Graf static void mmubooke_create_initial_mapping(CPUPPCState *env)
3683b989d49SAlexander Graf {
369cba2026aSAlexander Graf     struct boot_info *bi = env->load_info;
370d1e256feSAlexander Graf     ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0);
371cba2026aSAlexander Graf     target_phys_addr_t size, dt_end;
372cba2026aSAlexander Graf     int ps;
3733b989d49SAlexander Graf 
374cba2026aSAlexander Graf     /* Our initial TLB entry needs to cover everything from 0 to
375cba2026aSAlexander Graf        the device tree top */
376cba2026aSAlexander Graf     dt_end = bi->dt_base + bi->dt_size;
377cba2026aSAlexander Graf     ps = booke206_page_size_to_tlb(dt_end) + 1;
378cba2026aSAlexander Graf     size = (ps << MAS1_TSIZE_SHIFT);
379d1e256feSAlexander Graf     tlb->mas1 = MAS1_VALID | size;
380cba2026aSAlexander Graf     tlb->mas2 = 0;
381cba2026aSAlexander Graf     tlb->mas7_3 = 0;
382d1e256feSAlexander Graf     tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
38393dd5e85SScott Wood 
38493dd5e85SScott Wood     env->tlb_dirty = true;
3853b989d49SAlexander Graf }
3863b989d49SAlexander Graf 
387b3305981SScott Wood static void ppce500_cpu_reset_sec(void *opaque)
3885c145dacSAlexander Graf {
38938f92da6SAndreas Färber     PowerPCCPU *cpu = opaque;
39038f92da6SAndreas Färber     CPUPPCState *env = &cpu->env;
3915c145dacSAlexander Graf 
39238f92da6SAndreas Färber     cpu_reset(CPU(cpu));
3935c145dacSAlexander Graf 
3945c145dacSAlexander Graf     /* Secondary CPU starts in halted state for now. Needs to change when
3955c145dacSAlexander Graf        implementing non-kernel boot. */
3965c145dacSAlexander Graf     env->halted = 1;
3975c145dacSAlexander Graf     env->exception_index = EXCP_HLT;
3983b989d49SAlexander Graf }
3993b989d49SAlexander Graf 
400b3305981SScott Wood static void ppce500_cpu_reset(void *opaque)
4013b989d49SAlexander Graf {
40238f92da6SAndreas Färber     PowerPCCPU *cpu = opaque;
40338f92da6SAndreas Färber     CPUPPCState *env = &cpu->env;
4043b989d49SAlexander Graf     struct boot_info *bi = env->load_info;
4053b989d49SAlexander Graf 
40638f92da6SAndreas Färber     cpu_reset(CPU(cpu));
4073b989d49SAlexander Graf 
4083b989d49SAlexander Graf     /* Set initial guest state. */
4095c145dacSAlexander Graf     env->halted = 0;
4103b989d49SAlexander Graf     env->gpr[1] = (16<<20) - 8;
4113b989d49SAlexander Graf     env->gpr[3] = bi->dt_base;
4123b989d49SAlexander Graf     env->nip = bi->entry;
413cba2026aSAlexander Graf     mmubooke_create_initial_mapping(env);
4143b989d49SAlexander Graf }
4153b989d49SAlexander Graf 
416e6eaabebSScott Wood void ppce500_init(PPCE500Params *params)
4171db09b84Saurel32 {
41839186d8aSRichard Henderson     MemoryRegion *address_space_mem = get_system_memory();
4192646c133SAvi Kivity     MemoryRegion *ram = g_new(MemoryRegion, 1);
4201db09b84Saurel32     PCIBus *pci_bus;
421e2684c0bSAndreas Färber     CPUPPCState *env = NULL;
4221db09b84Saurel32     uint64_t elf_entry;
4231db09b84Saurel32     uint64_t elf_lowaddr;
424c227f099SAnthony Liguori     target_phys_addr_t entry=0;
425c227f099SAnthony Liguori     target_phys_addr_t loadaddr=UIMAGE_LOAD_BASE;
4261db09b84Saurel32     target_long kernel_size=0;
42775bb6589SLiu Yu     target_ulong dt_base = 0;
42875bb6589SLiu Yu     target_ulong initrd_base = 0;
4291db09b84Saurel32     target_long initrd_size=0;
4301db09b84Saurel32     int i=0;
4311db09b84Saurel32     unsigned int pci_irq_nrs[4] = {1, 2, 3, 4};
432a915249fSAlexander Graf     qemu_irq **irqs, *mpic;
433be13cc7aSAlexander Graf     DeviceState *dev;
434e2684c0bSAndreas Färber     CPUPPCState *firstenv = NULL;
4351db09b84Saurel32 
436e61c36d5SAlexander Graf     /* Setup CPUs */
437e6eaabebSScott Wood     if (params->cpu_model == NULL) {
438e6eaabebSScott Wood         params->cpu_model = "e500v2_v30";
439ef250db6SAlexander Graf     }
440ef250db6SAlexander Graf 
441a915249fSAlexander Graf     irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *));
442a915249fSAlexander Graf     irqs[0] = g_malloc0(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
443e61c36d5SAlexander Graf     for (i = 0; i < smp_cpus; i++) {
444397b457dSAndreas Färber         PowerPCCPU *cpu;
445e61c36d5SAlexander Graf         qemu_irq *input;
446397b457dSAndreas Färber 
447e6eaabebSScott Wood         cpu = cpu_ppc_init(params->cpu_model);
448397b457dSAndreas Färber         if (cpu == NULL) {
4491db09b84Saurel32             fprintf(stderr, "Unable to initialize CPU!\n");
4501db09b84Saurel32             exit(1);
4511db09b84Saurel32         }
452397b457dSAndreas Färber         env = &cpu->env;
4531db09b84Saurel32 
454e61c36d5SAlexander Graf         if (!firstenv) {
455e61c36d5SAlexander Graf             firstenv = env;
456e61c36d5SAlexander Graf         }
457e61c36d5SAlexander Graf 
458a915249fSAlexander Graf         irqs[i] = irqs[0] + (i * OPENPIC_OUTPUT_NB);
459a915249fSAlexander Graf         input = (qemu_irq *)env->irq_inputs;
460a915249fSAlexander Graf         irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT];
461a915249fSAlexander Graf         irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT];
462e61c36d5SAlexander Graf         env->spr[SPR_BOOKE_PIR] = env->cpu_index = i;
4632a7a47fcSAlexander Graf         env->mpic_cpu_base = MPC8544_MPIC_REGS_BASE + 0x20000;
464e61c36d5SAlexander Graf 
465ddd1055bSFabien Chouteau         ppc_booke_timers_init(env, 400000000, PPC_TIMER_E500);
4663b989d49SAlexander Graf 
4673b989d49SAlexander Graf         /* Register reset handler */
4685c145dacSAlexander Graf         if (!i) {
4695c145dacSAlexander Graf             /* Primary CPU */
4705c145dacSAlexander Graf             struct boot_info *boot_info;
471e61c36d5SAlexander Graf             boot_info = g_malloc0(sizeof(struct boot_info));
472b3305981SScott Wood             qemu_register_reset(ppce500_cpu_reset, cpu);
473e61c36d5SAlexander Graf             env->load_info = boot_info;
4745c145dacSAlexander Graf         } else {
4755c145dacSAlexander Graf             /* Secondary CPUs */
476b3305981SScott Wood             qemu_register_reset(ppce500_cpu_reset_sec, cpu);
4775c145dacSAlexander Graf         }
478e61c36d5SAlexander Graf     }
479e61c36d5SAlexander Graf 
480e61c36d5SAlexander Graf     env = firstenv;
4813b989d49SAlexander Graf 
4821db09b84Saurel32     /* Fixup Memory size on a alignment boundary */
4831db09b84Saurel32     ram_size &= ~(RAM_SIZES_ALIGN - 1);
4841db09b84Saurel32 
4851db09b84Saurel32     /* Register Memory */
486c5705a77SAvi Kivity     memory_region_init_ram(ram, "mpc8544ds.ram", ram_size);
487c5705a77SAvi Kivity     vmstate_register_ram_global(ram);
4882646c133SAvi Kivity     memory_region_add_subregion(address_space_mem, 0, ram);
4891db09b84Saurel32 
4901db09b84Saurel32     /* MPIC */
491df2921d3SAvi Kivity     mpic = mpic_init(address_space_mem, MPC8544_MPIC_REGS_BASE,
492df2921d3SAvi Kivity                      smp_cpus, irqs, NULL);
493a915249fSAlexander Graf 
494a915249fSAlexander Graf     if (!mpic) {
495a915249fSAlexander Graf         cpu_abort(env, "MPIC failed to initialize\n");
496a915249fSAlexander Graf     }
4971db09b84Saurel32 
4981db09b84Saurel32     /* Serial */
4992d48377aSBlue Swirl     if (serial_hds[0]) {
50039186d8aSRichard Henderson         serial_mm_init(address_space_mem, MPC8544_SERIAL0_REGS_BASE,
5011db09b84Saurel32                        0, mpic[12+26], 399193,
5022ff0c7c3SRichard Henderson                        serial_hds[0], DEVICE_BIG_ENDIAN);
5032d48377aSBlue Swirl     }
5041db09b84Saurel32 
5052d48377aSBlue Swirl     if (serial_hds[1]) {
50639186d8aSRichard Henderson         serial_mm_init(address_space_mem, MPC8544_SERIAL1_REGS_BASE,
5071db09b84Saurel32                        0, mpic[12+26], 399193,
5082ff0c7c3SRichard Henderson                        serial_hds[0], DEVICE_BIG_ENDIAN);
5092d48377aSBlue Swirl     }
5101db09b84Saurel32 
511b0fb8423SAlexander Graf     /* General Utility device */
512b0fb8423SAlexander Graf     sysbus_create_simple("mpc8544-guts", MPC8544_UTIL_BASE, NULL);
513b0fb8423SAlexander Graf 
5141db09b84Saurel32     /* PCI */
515be13cc7aSAlexander Graf     dev = sysbus_create_varargs("e500-pcihost", MPC8544_PCI_REGS_BASE,
516be13cc7aSAlexander Graf                                 mpic[pci_irq_nrs[0]], mpic[pci_irq_nrs[1]],
517be13cc7aSAlexander Graf                                 mpic[pci_irq_nrs[2]], mpic[pci_irq_nrs[3]],
518be13cc7aSAlexander Graf                                 NULL);
519d461e3b9SAlexander Graf     pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
5201db09b84Saurel32     if (!pci_bus)
5211db09b84Saurel32         printf("couldn't create PCI controller!\n");
5221db09b84Saurel32 
523968d683cSAlexander Graf     isa_mmio_init(MPC8544_PCI_IO, MPC8544_PCI_IOLEN);
5241db09b84Saurel32 
5251db09b84Saurel32     if (pci_bus) {
5261db09b84Saurel32         /* Register network interfaces. */
5271db09b84Saurel32         for (i = 0; i < nb_nics; i++) {
52807caea31SMarkus Armbruster             pci_nic_init_nofail(&nd_table[i], "virtio", NULL);
5291db09b84Saurel32         }
5301db09b84Saurel32     }
5311db09b84Saurel32 
5325c145dacSAlexander Graf     /* Register spinning region */
5335c145dacSAlexander Graf     sysbus_create_simple("e500-spin", MPC8544_SPIN_BASE, NULL);
5345c145dacSAlexander Graf 
5351db09b84Saurel32     /* Load kernel. */
536e6eaabebSScott Wood     if (params->kernel_filename) {
537e6eaabebSScott Wood         kernel_size = load_uimage(params->kernel_filename, &entry,
538e6eaabebSScott Wood                                   &loadaddr, NULL);
5391db09b84Saurel32         if (kernel_size < 0) {
540e6eaabebSScott Wood             kernel_size = load_elf(params->kernel_filename, NULL, NULL,
541e6eaabebSScott Wood                                    &elf_entry, &elf_lowaddr, NULL, 1,
542e6eaabebSScott Wood                                    ELF_MACHINE, 0);
5431db09b84Saurel32             entry = elf_entry;
5441db09b84Saurel32             loadaddr = elf_lowaddr;
5451db09b84Saurel32         }
5461db09b84Saurel32         /* XXX try again as binary */
5471db09b84Saurel32         if (kernel_size < 0) {
5481db09b84Saurel32             fprintf(stderr, "qemu: could not load kernel '%s'\n",
549e6eaabebSScott Wood                     params->kernel_filename);
5501db09b84Saurel32             exit(1);
5511db09b84Saurel32         }
5521db09b84Saurel32     }
5531db09b84Saurel32 
5541db09b84Saurel32     /* Load initrd. */
555e6eaabebSScott Wood     if (params->initrd_filename) {
55675bb6589SLiu Yu         initrd_base = (kernel_size + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK;
557e6eaabebSScott Wood         initrd_size = load_image_targphys(params->initrd_filename, initrd_base,
558d7585251Spbrook                                           ram_size - initrd_base);
5591db09b84Saurel32 
5601db09b84Saurel32         if (initrd_size < 0) {
5611db09b84Saurel32             fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
562e6eaabebSScott Wood                     params->initrd_filename);
5631db09b84Saurel32             exit(1);
5641db09b84Saurel32         }
5651db09b84Saurel32     }
5661db09b84Saurel32 
5671db09b84Saurel32     /* If we're loading a kernel directly, we must load the device tree too. */
568e6eaabebSScott Wood     if (params->kernel_filename) {
5695c145dacSAlexander Graf         struct boot_info *boot_info;
570cba2026aSAlexander Graf         int dt_size;
5715c145dacSAlexander Graf 
572cba2026aSAlexander Graf         dt_base = (loadaddr + kernel_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
573e6eaabebSScott Wood         dt_size = ppce500_load_device_tree(env, params, dt_base, initrd_base,
574e6eaabebSScott Wood                                            initrd_size);
575cba2026aSAlexander Graf         if (dt_size < 0) {
5761db09b84Saurel32             fprintf(stderr, "couldn't load device tree\n");
5771db09b84Saurel32             exit(1);
5781db09b84Saurel32         }
5791db09b84Saurel32 
580e61c36d5SAlexander Graf         boot_info = env->load_info;
5813b989d49SAlexander Graf         boot_info->entry = entry;
5823b989d49SAlexander Graf         boot_info->dt_base = dt_base;
583cba2026aSAlexander Graf         boot_info->dt_size = dt_size;
5841db09b84Saurel32     }
5851db09b84Saurel32 
5863b989d49SAlexander Graf     if (kvm_enabled()) {
5871db09b84Saurel32         kvmppc_init();
5883b989d49SAlexander Graf     }
5891db09b84Saurel32 }
590