xref: /qemu/hw/ppc/e500.c (revision e6eaabeb8dfb026da51d178974bddf56f1f06ffe)
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"
19*e6eaabebSScott 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 */
71518c7fb4SAlexander Graf                              0x8800, 0x0, 0x0, 0x1, mpic, 0x2, 0x1, 0x0, 0x0,
72518c7fb4SAlexander Graf                              0x8800, 0x0, 0x0, 0x2, mpic, 0x3, 0x1, 0x0, 0x0,
73518c7fb4SAlexander Graf                              0x8800, 0x0, 0x0, 0x3, mpic, 0x4, 0x1, 0x0, 0x0,
74518c7fb4SAlexander Graf                              0x8800, 0x0, 0x0, 0x4, mpic, 0x1, 0x1, 0x0, 0x0,
750dbc0798SAlexander Graf 
760dbc0798SAlexander Graf                              /* IDSEL 0x12 J16 Slot 2 */
77518c7fb4SAlexander Graf                              0x9000, 0x0, 0x0, 0x1, mpic, 0x3, 0x1, 0x0, 0x0,
78518c7fb4SAlexander Graf                              0x9000, 0x0, 0x0, 0x2, mpic, 0x4, 0x1, 0x0, 0x0,
79518c7fb4SAlexander Graf                              0x9000, 0x0, 0x0, 0x3, mpic, 0x2, 0x1, 0x0, 0x0,
80518c7fb4SAlexander Graf                              0x9000, 0x0, 0x0, 0x4, mpic, 0x1, 0x1, 0x0, 0x0,
810dbc0798SAlexander Graf                            };
82518c7fb4SAlexander Graf     for (i = 0; i < ARRAY_SIZE(tmp); 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);
100a053a7ceSAlexander Graf     qemu_devtree_setprop_cells(fdt, ser, "interrupts", 42, 2, 0, 0);
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,
110*e6eaabebSScott Wood                                     PPCE500Params *params,
1115de6b46dSAlexander Graf                                     target_phys_addr_t addr,
112c227f099SAnthony Liguori                                     target_phys_addr_t initrd_base,
113*e6eaabebSScott Wood                                     target_phys_addr_t initrd_size)
1141db09b84Saurel32 {
115dbf916d8SAurelien Jarno     int ret = -1;
116*e6eaabebSScott 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;
123*e6eaabebSScott 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];
130518c7fb4SAlexander Graf     uint32_t pci_map[9 * 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");
149*e6eaabebSScott 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",
196*e6eaabebSScott 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");
277518c7fb4SAlexander Graf     qemu_devtree_setprop_string(fdt, mpic, "compatible", "fsl,mpic");
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);
281518c7fb4SAlexander Graf     qemu_devtree_setprop_cell(fdt, mpic, "#interrupt-cells", 4);
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);
286518c7fb4SAlexander Graf     qemu_devtree_setprop(fdt, mpic, "big-endian", NULL, 0);
287518c7fb4SAlexander Graf     qemu_devtree_setprop(fdt, mpic, "single-cpu-affinity", NULL, 0);
288518c7fb4SAlexander Graf     qemu_devtree_setprop_cell(fdt, mpic, "last-interrupt-source", 255);
28919ac9deaSAlexander Graf 
2900cfc6e8dSAlexander Graf     /*
2910cfc6e8dSAlexander Graf      * We have to generate ser1 first, because Linux takes the first
2920cfc6e8dSAlexander Graf      * device it finds in the dt as serial output device. And we generate
2930cfc6e8dSAlexander Graf      * devices in reverse order to the dt.
2940cfc6e8dSAlexander Graf      */
295a053a7ceSAlexander Graf     dt_serial_create(fdt, MPC8544_SERIAL1_REGS_BASE - MPC8544_CCSRBAR_BASE,
296a053a7ceSAlexander Graf                      soc, mpic, "serial1", 1, false);
297a053a7ceSAlexander Graf     dt_serial_create(fdt, MPC8544_SERIAL0_REGS_BASE - MPC8544_CCSRBAR_BASE,
298a053a7ceSAlexander Graf                      soc, mpic, "serial0", 0, true);
2990cfc6e8dSAlexander Graf 
300ed2bc496SAlexander Graf     snprintf(gutil, sizeof(gutil), "%s/global-utilities@%llx", soc,
301f5038483SAlexander Graf              MPC8544_UTIL_BASE - MPC8544_CCSRBAR_BASE);
302f5038483SAlexander Graf     qemu_devtree_add_subnode(fdt, gutil);
303f5038483SAlexander Graf     qemu_devtree_setprop_string(fdt, gutil, "compatible", "fsl,mpc8544-guts");
304f5038483SAlexander Graf     qemu_devtree_setprop_cells(fdt, gutil, "reg", MPC8544_UTIL_BASE -
305f5038483SAlexander Graf                                MPC8544_CCSRBAR_BASE, 0x1000);
306f5038483SAlexander Graf     qemu_devtree_setprop(fdt, gutil, "fsl,has-rstcr", NULL, 0);
307f5038483SAlexander Graf 
308ed2bc496SAlexander Graf     snprintf(pci, sizeof(pci), "/pci@%llx", MPC8544_PCI_REGS_BASE);
3090dbc0798SAlexander Graf     qemu_devtree_add_subnode(fdt, pci);
3100dbc0798SAlexander Graf     qemu_devtree_setprop_cell(fdt, pci, "cell-index", 0);
3110dbc0798SAlexander Graf     qemu_devtree_setprop_string(fdt, pci, "compatible", "fsl,mpc8540-pci");
3120dbc0798SAlexander Graf     qemu_devtree_setprop_string(fdt, pci, "device_type", "pci");
3130dbc0798SAlexander Graf     qemu_devtree_setprop_cells(fdt, pci, "interrupt-map-mask", 0xf800, 0x0,
3140dbc0798SAlexander Graf                                0x0, 0x7);
3150dbc0798SAlexander Graf     pci_map_create(fdt, pci_map, qemu_devtree_get_phandle(fdt, mpic));
3160dbc0798SAlexander Graf     qemu_devtree_setprop(fdt, pci, "interrupt-map", pci_map, sizeof(pci_map));
3170dbc0798SAlexander Graf     qemu_devtree_setprop_phandle(fdt, pci, "interrupt-parent", mpic);
318518c7fb4SAlexander Graf     qemu_devtree_setprop_cells(fdt, pci, "interrupts", 24, 2, 0, 0);
3190dbc0798SAlexander Graf     qemu_devtree_setprop_cells(fdt, pci, "bus-range", 0, 255);
3203627757eSAlexander Graf     for (i = 0; i < 14; i++) {
3210dbc0798SAlexander Graf         pci_ranges[i] = cpu_to_be32(pci_ranges[i]);
3220dbc0798SAlexander Graf     }
3230dbc0798SAlexander Graf     qemu_devtree_setprop(fdt, pci, "ranges", pci_ranges, sizeof(pci_ranges));
3243627757eSAlexander Graf     qemu_devtree_setprop_cells(fdt, pci, "reg", MPC8544_PCI_REGS_BASE >> 32,
3253627757eSAlexander Graf                                MPC8544_PCI_REGS_BASE, 0, 0x1000);
3260dbc0798SAlexander Graf     qemu_devtree_setprop_cell(fdt, pci, "clock-frequency", 66666666);
3270dbc0798SAlexander Graf     qemu_devtree_setprop_cell(fdt, pci, "#interrupt-cells", 1);
3280dbc0798SAlexander Graf     qemu_devtree_setprop_cell(fdt, pci, "#size-cells", 2);
3290dbc0798SAlexander Graf     qemu_devtree_setprop_cell(fdt, pci, "#address-cells", 3);
3300dbc0798SAlexander Graf     qemu_devtree_setprop_string(fdt, "/aliases", "pci0", pci);
3310dbc0798SAlexander Graf 
332*e6eaabebSScott Wood     params->fixup_devtree(params, fdt);
333*e6eaabebSScott Wood 
334*e6eaabebSScott Wood     if (toplevel_compat) {
335*e6eaabebSScott Wood         qemu_devtree_setprop(fdt, "/", "compatible", toplevel_compat,
336*e6eaabebSScott Wood                              strlen(toplevel_compat) + 1);
337*e6eaabebSScott Wood     }
338*e6eaabebSScott Wood 
339d1b93565SAlexander Graf done:
34025b42708SAlexander Graf     if (dumpdtb) {
34125b42708SAlexander Graf         /* Dump the dtb to a file and quit */
34225b42708SAlexander Graf         FILE *f = fopen(dumpdtb, "wb");
34325b42708SAlexander Graf         size_t len;
34425b42708SAlexander Graf         len = fwrite(fdt, fdt_size, 1, f);
34525b42708SAlexander Graf         fclose(f);
34625b42708SAlexander Graf         if (len != fdt_size) {
34725b42708SAlexander Graf             exit(1);
34825b42708SAlexander Graf         }
34925b42708SAlexander Graf         exit(0);
35025b42708SAlexander Graf     }
35125b42708SAlexander Graf 
35204088adbSLiu Yu     ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
353cba2026aSAlexander Graf     if (ret < 0) {
354cba2026aSAlexander Graf         goto out;
355cba2026aSAlexander Graf     }
3567267c094SAnthony Liguori     g_free(fdt);
357cba2026aSAlexander Graf     ret = fdt_size;
3587ec632b4Spbrook 
3591db09b84Saurel32 out:
3601db09b84Saurel32 
36104088adbSLiu Yu     return ret;
3621db09b84Saurel32 }
3631db09b84Saurel32 
364cba2026aSAlexander Graf /* Create -kernel TLB entries for BookE.  */
365d1e256feSAlexander Graf static inline target_phys_addr_t booke206_page_size_to_tlb(uint64_t size)
366d1e256feSAlexander Graf {
367cba2026aSAlexander Graf     return 63 - clz64(size >> 10);
368d1e256feSAlexander Graf }
369d1e256feSAlexander Graf 
370cba2026aSAlexander Graf static void mmubooke_create_initial_mapping(CPUPPCState *env)
3713b989d49SAlexander Graf {
372cba2026aSAlexander Graf     struct boot_info *bi = env->load_info;
373d1e256feSAlexander Graf     ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0);
374cba2026aSAlexander Graf     target_phys_addr_t size, dt_end;
375cba2026aSAlexander Graf     int ps;
3763b989d49SAlexander Graf 
377cba2026aSAlexander Graf     /* Our initial TLB entry needs to cover everything from 0 to
378cba2026aSAlexander Graf        the device tree top */
379cba2026aSAlexander Graf     dt_end = bi->dt_base + bi->dt_size;
380cba2026aSAlexander Graf     ps = booke206_page_size_to_tlb(dt_end) + 1;
381cba2026aSAlexander Graf     size = (ps << MAS1_TSIZE_SHIFT);
382d1e256feSAlexander Graf     tlb->mas1 = MAS1_VALID | size;
383cba2026aSAlexander Graf     tlb->mas2 = 0;
384cba2026aSAlexander Graf     tlb->mas7_3 = 0;
385d1e256feSAlexander Graf     tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
38693dd5e85SScott Wood 
38793dd5e85SScott Wood     env->tlb_dirty = true;
3883b989d49SAlexander Graf }
3893b989d49SAlexander Graf 
390b3305981SScott Wood static void ppce500_cpu_reset_sec(void *opaque)
3915c145dacSAlexander Graf {
39238f92da6SAndreas Färber     PowerPCCPU *cpu = opaque;
39338f92da6SAndreas Färber     CPUPPCState *env = &cpu->env;
3945c145dacSAlexander Graf 
39538f92da6SAndreas Färber     cpu_reset(CPU(cpu));
3965c145dacSAlexander Graf 
3975c145dacSAlexander Graf     /* Secondary CPU starts in halted state for now. Needs to change when
3985c145dacSAlexander Graf        implementing non-kernel boot. */
3995c145dacSAlexander Graf     env->halted = 1;
4005c145dacSAlexander Graf     env->exception_index = EXCP_HLT;
4013b989d49SAlexander Graf }
4023b989d49SAlexander Graf 
403b3305981SScott Wood static void ppce500_cpu_reset(void *opaque)
4043b989d49SAlexander Graf {
40538f92da6SAndreas Färber     PowerPCCPU *cpu = opaque;
40638f92da6SAndreas Färber     CPUPPCState *env = &cpu->env;
4073b989d49SAlexander Graf     struct boot_info *bi = env->load_info;
4083b989d49SAlexander Graf 
40938f92da6SAndreas Färber     cpu_reset(CPU(cpu));
4103b989d49SAlexander Graf 
4113b989d49SAlexander Graf     /* Set initial guest state. */
4125c145dacSAlexander Graf     env->halted = 0;
4133b989d49SAlexander Graf     env->gpr[1] = (16<<20) - 8;
4143b989d49SAlexander Graf     env->gpr[3] = bi->dt_base;
4153b989d49SAlexander Graf     env->nip = bi->entry;
416cba2026aSAlexander Graf     mmubooke_create_initial_mapping(env);
4173b989d49SAlexander Graf }
4183b989d49SAlexander Graf 
419*e6eaabebSScott Wood void ppce500_init(PPCE500Params *params)
4201db09b84Saurel32 {
42139186d8aSRichard Henderson     MemoryRegion *address_space_mem = get_system_memory();
4222646c133SAvi Kivity     MemoryRegion *ram = g_new(MemoryRegion, 1);
4231db09b84Saurel32     PCIBus *pci_bus;
424e2684c0bSAndreas Färber     CPUPPCState *env = NULL;
4251db09b84Saurel32     uint64_t elf_entry;
4261db09b84Saurel32     uint64_t elf_lowaddr;
427c227f099SAnthony Liguori     target_phys_addr_t entry=0;
428c227f099SAnthony Liguori     target_phys_addr_t loadaddr=UIMAGE_LOAD_BASE;
4291db09b84Saurel32     target_long kernel_size=0;
43075bb6589SLiu Yu     target_ulong dt_base = 0;
43175bb6589SLiu Yu     target_ulong initrd_base = 0;
4321db09b84Saurel32     target_long initrd_size=0;
4331db09b84Saurel32     int i=0;
4341db09b84Saurel32     unsigned int pci_irq_nrs[4] = {1, 2, 3, 4};
435a915249fSAlexander Graf     qemu_irq **irqs, *mpic;
436be13cc7aSAlexander Graf     DeviceState *dev;
437e2684c0bSAndreas Färber     CPUPPCState *firstenv = NULL;
4381db09b84Saurel32 
439e61c36d5SAlexander Graf     /* Setup CPUs */
440*e6eaabebSScott Wood     if (params->cpu_model == NULL) {
441*e6eaabebSScott Wood         params->cpu_model = "e500v2_v30";
442ef250db6SAlexander Graf     }
443ef250db6SAlexander Graf 
444a915249fSAlexander Graf     irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *));
445a915249fSAlexander Graf     irqs[0] = g_malloc0(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
446e61c36d5SAlexander Graf     for (i = 0; i < smp_cpus; i++) {
447397b457dSAndreas Färber         PowerPCCPU *cpu;
448e61c36d5SAlexander Graf         qemu_irq *input;
449397b457dSAndreas Färber 
450*e6eaabebSScott Wood         cpu = cpu_ppc_init(params->cpu_model);
451397b457dSAndreas Färber         if (cpu == NULL) {
4521db09b84Saurel32             fprintf(stderr, "Unable to initialize CPU!\n");
4531db09b84Saurel32             exit(1);
4541db09b84Saurel32         }
455397b457dSAndreas Färber         env = &cpu->env;
4561db09b84Saurel32 
457e61c36d5SAlexander Graf         if (!firstenv) {
458e61c36d5SAlexander Graf             firstenv = env;
459e61c36d5SAlexander Graf         }
460e61c36d5SAlexander Graf 
461a915249fSAlexander Graf         irqs[i] = irqs[0] + (i * OPENPIC_OUTPUT_NB);
462a915249fSAlexander Graf         input = (qemu_irq *)env->irq_inputs;
463a915249fSAlexander Graf         irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT];
464a915249fSAlexander Graf         irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT];
465e61c36d5SAlexander Graf         env->spr[SPR_BOOKE_PIR] = env->cpu_index = i;
4662a7a47fcSAlexander Graf         env->mpic_cpu_base = MPC8544_MPIC_REGS_BASE + 0x20000;
467e61c36d5SAlexander Graf 
468ddd1055bSFabien Chouteau         ppc_booke_timers_init(env, 400000000, PPC_TIMER_E500);
4693b989d49SAlexander Graf 
4703b989d49SAlexander Graf         /* Register reset handler */
4715c145dacSAlexander Graf         if (!i) {
4725c145dacSAlexander Graf             /* Primary CPU */
4735c145dacSAlexander Graf             struct boot_info *boot_info;
474e61c36d5SAlexander Graf             boot_info = g_malloc0(sizeof(struct boot_info));
475b3305981SScott Wood             qemu_register_reset(ppce500_cpu_reset, cpu);
476e61c36d5SAlexander Graf             env->load_info = boot_info;
4775c145dacSAlexander Graf         } else {
4785c145dacSAlexander Graf             /* Secondary CPUs */
479b3305981SScott Wood             qemu_register_reset(ppce500_cpu_reset_sec, cpu);
4805c145dacSAlexander Graf         }
481e61c36d5SAlexander Graf     }
482e61c36d5SAlexander Graf 
483e61c36d5SAlexander Graf     env = firstenv;
4843b989d49SAlexander Graf 
4851db09b84Saurel32     /* Fixup Memory size on a alignment boundary */
4861db09b84Saurel32     ram_size &= ~(RAM_SIZES_ALIGN - 1);
4871db09b84Saurel32 
4881db09b84Saurel32     /* Register Memory */
489c5705a77SAvi Kivity     memory_region_init_ram(ram, "mpc8544ds.ram", ram_size);
490c5705a77SAvi Kivity     vmstate_register_ram_global(ram);
4912646c133SAvi Kivity     memory_region_add_subregion(address_space_mem, 0, ram);
4921db09b84Saurel32 
4931db09b84Saurel32     /* MPIC */
494df2921d3SAvi Kivity     mpic = mpic_init(address_space_mem, MPC8544_MPIC_REGS_BASE,
495df2921d3SAvi Kivity                      smp_cpus, irqs, NULL);
496a915249fSAlexander Graf 
497a915249fSAlexander Graf     if (!mpic) {
498a915249fSAlexander Graf         cpu_abort(env, "MPIC failed to initialize\n");
499a915249fSAlexander Graf     }
5001db09b84Saurel32 
5011db09b84Saurel32     /* Serial */
5022d48377aSBlue Swirl     if (serial_hds[0]) {
50339186d8aSRichard Henderson         serial_mm_init(address_space_mem, MPC8544_SERIAL0_REGS_BASE,
5041db09b84Saurel32                        0, mpic[12+26], 399193,
5052ff0c7c3SRichard Henderson                        serial_hds[0], DEVICE_BIG_ENDIAN);
5062d48377aSBlue Swirl     }
5071db09b84Saurel32 
5082d48377aSBlue Swirl     if (serial_hds[1]) {
50939186d8aSRichard Henderson         serial_mm_init(address_space_mem, MPC8544_SERIAL1_REGS_BASE,
5101db09b84Saurel32                        0, mpic[12+26], 399193,
5112ff0c7c3SRichard Henderson                        serial_hds[0], DEVICE_BIG_ENDIAN);
5122d48377aSBlue Swirl     }
5131db09b84Saurel32 
514b0fb8423SAlexander Graf     /* General Utility device */
515b0fb8423SAlexander Graf     sysbus_create_simple("mpc8544-guts", MPC8544_UTIL_BASE, NULL);
516b0fb8423SAlexander Graf 
5171db09b84Saurel32     /* PCI */
518be13cc7aSAlexander Graf     dev = sysbus_create_varargs("e500-pcihost", MPC8544_PCI_REGS_BASE,
519be13cc7aSAlexander Graf                                 mpic[pci_irq_nrs[0]], mpic[pci_irq_nrs[1]],
520be13cc7aSAlexander Graf                                 mpic[pci_irq_nrs[2]], mpic[pci_irq_nrs[3]],
521be13cc7aSAlexander Graf                                 NULL);
522d461e3b9SAlexander Graf     pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
5231db09b84Saurel32     if (!pci_bus)
5241db09b84Saurel32         printf("couldn't create PCI controller!\n");
5251db09b84Saurel32 
526968d683cSAlexander Graf     isa_mmio_init(MPC8544_PCI_IO, MPC8544_PCI_IOLEN);
5271db09b84Saurel32 
5281db09b84Saurel32     if (pci_bus) {
5291db09b84Saurel32         /* Register network interfaces. */
5301db09b84Saurel32         for (i = 0; i < nb_nics; i++) {
53107caea31SMarkus Armbruster             pci_nic_init_nofail(&nd_table[i], "virtio", NULL);
5321db09b84Saurel32         }
5331db09b84Saurel32     }
5341db09b84Saurel32 
5355c145dacSAlexander Graf     /* Register spinning region */
5365c145dacSAlexander Graf     sysbus_create_simple("e500-spin", MPC8544_SPIN_BASE, NULL);
5375c145dacSAlexander Graf 
5381db09b84Saurel32     /* Load kernel. */
539*e6eaabebSScott Wood     if (params->kernel_filename) {
540*e6eaabebSScott Wood         kernel_size = load_uimage(params->kernel_filename, &entry,
541*e6eaabebSScott Wood                                   &loadaddr, NULL);
5421db09b84Saurel32         if (kernel_size < 0) {
543*e6eaabebSScott Wood             kernel_size = load_elf(params->kernel_filename, NULL, NULL,
544*e6eaabebSScott Wood                                    &elf_entry, &elf_lowaddr, NULL, 1,
545*e6eaabebSScott Wood                                    ELF_MACHINE, 0);
5461db09b84Saurel32             entry = elf_entry;
5471db09b84Saurel32             loadaddr = elf_lowaddr;
5481db09b84Saurel32         }
5491db09b84Saurel32         /* XXX try again as binary */
5501db09b84Saurel32         if (kernel_size < 0) {
5511db09b84Saurel32             fprintf(stderr, "qemu: could not load kernel '%s'\n",
552*e6eaabebSScott Wood                     params->kernel_filename);
5531db09b84Saurel32             exit(1);
5541db09b84Saurel32         }
5551db09b84Saurel32     }
5561db09b84Saurel32 
5571db09b84Saurel32     /* Load initrd. */
558*e6eaabebSScott Wood     if (params->initrd_filename) {
55975bb6589SLiu Yu         initrd_base = (kernel_size + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK;
560*e6eaabebSScott Wood         initrd_size = load_image_targphys(params->initrd_filename, initrd_base,
561d7585251Spbrook                                           ram_size - initrd_base);
5621db09b84Saurel32 
5631db09b84Saurel32         if (initrd_size < 0) {
5641db09b84Saurel32             fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
565*e6eaabebSScott Wood                     params->initrd_filename);
5661db09b84Saurel32             exit(1);
5671db09b84Saurel32         }
5681db09b84Saurel32     }
5691db09b84Saurel32 
5701db09b84Saurel32     /* If we're loading a kernel directly, we must load the device tree too. */
571*e6eaabebSScott Wood     if (params->kernel_filename) {
5725c145dacSAlexander Graf         struct boot_info *boot_info;
573cba2026aSAlexander Graf         int dt_size;
5745c145dacSAlexander Graf 
575cba2026aSAlexander Graf         dt_base = (loadaddr + kernel_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
576*e6eaabebSScott Wood         dt_size = ppce500_load_device_tree(env, params, dt_base, initrd_base,
577*e6eaabebSScott Wood                                            initrd_size);
578cba2026aSAlexander Graf         if (dt_size < 0) {
5791db09b84Saurel32             fprintf(stderr, "couldn't load device tree\n");
5801db09b84Saurel32             exit(1);
5811db09b84Saurel32         }
5821db09b84Saurel32 
583e61c36d5SAlexander Graf         boot_info = env->load_info;
5843b989d49SAlexander Graf         boot_info->entry = entry;
5853b989d49SAlexander Graf         boot_info->dt_base = dt_base;
586cba2026aSAlexander Graf         boot_info->dt_size = dt_size;
5871db09b84Saurel32     }
5881db09b84Saurel32 
5893b989d49SAlexander Graf     if (kvm_enabled()) {
5901db09b84Saurel32         kvmppc_init();
5913b989d49SAlexander Graf     }
5921db09b84Saurel32 }
593