xref: /qemu/hw/ppc/e500.c (revision a1bc20dfbb012ea2a5fb1228cb77abd04490fd79)
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"
22488cb996SGerd Hoffmann #include "hw/serial.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
399dd5eba1SScott Wood #define DTC_LOAD_PAD               0x1800000
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_UTIL_BASE          (MPC8544_CCSRBAR_BASE + 0xe0000ULL)
56ed2bc496SAlexander Graf #define MPC8544_SPIN_BASE          0xEF000000ULL
571db09b84Saurel32 
583b989d49SAlexander Graf struct boot_info
593b989d49SAlexander Graf {
603b989d49SAlexander Graf     uint32_t dt_base;
61cba2026aSAlexander Graf     uint32_t dt_size;
623b989d49SAlexander Graf     uint32_t entry;
633b989d49SAlexander Graf };
643b989d49SAlexander Graf 
650dbc0798SAlexander Graf static void pci_map_create(void *fdt, uint32_t *pci_map, uint32_t mpic)
660dbc0798SAlexander Graf {
670dbc0798SAlexander Graf     int i;
680dbc0798SAlexander Graf     const uint32_t tmp[] = {
690dbc0798SAlexander Graf                              /* IDSEL 0x11 J17 Slot 1 */
707e99826cSAlexander Graf                              0x8800, 0x0, 0x0, 0x1, mpic, 0x2, 0x1,
717e99826cSAlexander Graf                              0x8800, 0x0, 0x0, 0x2, mpic, 0x3, 0x1,
727e99826cSAlexander Graf                              0x8800, 0x0, 0x0, 0x3, mpic, 0x4, 0x1,
737e99826cSAlexander Graf                              0x8800, 0x0, 0x0, 0x4, mpic, 0x1, 0x1,
740dbc0798SAlexander Graf 
750dbc0798SAlexander Graf                              /* IDSEL 0x12 J16 Slot 2 */
767e99826cSAlexander Graf                              0x9000, 0x0, 0x0, 0x1, mpic, 0x3, 0x1,
777e99826cSAlexander Graf                              0x9000, 0x0, 0x0, 0x2, mpic, 0x4, 0x1,
787e99826cSAlexander Graf                              0x9000, 0x0, 0x0, 0x3, mpic, 0x2, 0x1,
797e99826cSAlexander Graf                              0x9000, 0x0, 0x0, 0x4, mpic, 0x1, 0x1,
800dbc0798SAlexander Graf                            };
817e99826cSAlexander Graf     for (i = 0; i < (7 * 8); i++) {
820dbc0798SAlexander Graf         pci_map[i] = cpu_to_be32(tmp[i]);
830dbc0798SAlexander Graf     }
840dbc0798SAlexander Graf }
850dbc0798SAlexander Graf 
86a053a7ceSAlexander Graf static void dt_serial_create(void *fdt, unsigned long long offset,
87a053a7ceSAlexander Graf                              const char *soc, const char *mpic,
88a053a7ceSAlexander Graf                              const char *alias, int idx, bool defcon)
89a053a7ceSAlexander Graf {
90a053a7ceSAlexander Graf     char ser[128];
91a053a7ceSAlexander Graf 
92a053a7ceSAlexander Graf     snprintf(ser, sizeof(ser), "%s/serial@%llx", soc, offset);
93a053a7ceSAlexander Graf     qemu_devtree_add_subnode(fdt, ser);
94a053a7ceSAlexander Graf     qemu_devtree_setprop_string(fdt, ser, "device_type", "serial");
95a053a7ceSAlexander Graf     qemu_devtree_setprop_string(fdt, ser, "compatible", "ns16550");
96a053a7ceSAlexander Graf     qemu_devtree_setprop_cells(fdt, ser, "reg", offset, 0x100);
97a053a7ceSAlexander Graf     qemu_devtree_setprop_cell(fdt, ser, "cell-index", idx);
98a053a7ceSAlexander Graf     qemu_devtree_setprop_cell(fdt, ser, "clock-frequency", 0);
997e99826cSAlexander Graf     qemu_devtree_setprop_cells(fdt, ser, "interrupts", 42, 2);
100a053a7ceSAlexander Graf     qemu_devtree_setprop_phandle(fdt, ser, "interrupt-parent", mpic);
101a053a7ceSAlexander Graf     qemu_devtree_setprop_string(fdt, "/aliases", alias, ser);
102a053a7ceSAlexander Graf 
103a053a7ceSAlexander Graf     if (defcon) {
104a053a7ceSAlexander Graf         qemu_devtree_setprop_string(fdt, "/chosen", "linux,stdout-path", ser);
105a053a7ceSAlexander Graf     }
106a053a7ceSAlexander Graf }
107a053a7ceSAlexander Graf 
108b3305981SScott Wood static int ppce500_load_device_tree(CPUPPCState *env,
109e6eaabebSScott Wood                                     PPCE500Params *params,
110a8170e5eSAvi Kivity                                     hwaddr addr,
111a8170e5eSAvi Kivity                                     hwaddr initrd_base,
112a8170e5eSAvi Kivity                                     hwaddr initrd_size)
1131db09b84Saurel32 {
114dbf916d8SAurelien Jarno     int ret = -1;
115e6eaabebSScott Wood     uint64_t mem_reg_property[] = { 0, cpu_to_be64(params->ram_size) };
1167ec632b4Spbrook     int fdt_size;
117dbf916d8SAurelien Jarno     void *fdt;
1185de6b46dSAlexander Graf     uint8_t hypercall[16];
119911d6e7aSAlexander Graf     uint32_t clock_freq = 400000000;
120911d6e7aSAlexander Graf     uint32_t tb_freq = 400000000;
121621d05e3SAlexander Graf     int i;
122e6eaabebSScott Wood     const char *toplevel_compat = NULL; /* user override */
123ebb9518aSAlexander Graf     char compatible_sb[] = "fsl,mpc8544-immr\0simple-bus";
1245da96624SAlexander Graf     char soc[128];
12519ac9deaSAlexander Graf     char mpic[128];
12619ac9deaSAlexander Graf     uint32_t mpic_ph;
127f5038483SAlexander Graf     char gutil[128];
1280dbc0798SAlexander Graf     char pci[128];
1297e99826cSAlexander Graf     uint32_t pci_map[7 * 8];
1303627757eSAlexander Graf     uint32_t pci_ranges[14] =
1313627757eSAlexander Graf         {
1323627757eSAlexander Graf             0x2000000, 0x0, 0xc0000000,
1333627757eSAlexander Graf             0x0, 0xc0000000,
1343627757eSAlexander Graf             0x0, 0x20000000,
1353627757eSAlexander Graf 
1363627757eSAlexander Graf             0x1000000, 0x0, 0x0,
1373627757eSAlexander Graf             0x0, 0xe1000000,
1383627757eSAlexander Graf             0x0, 0x10000,
1393627757eSAlexander Graf         };
14025b42708SAlexander Graf     QemuOpts *machine_opts;
141d1b93565SAlexander Graf     const char *dtb_file = NULL;
142d1b93565SAlexander Graf 
143d1b93565SAlexander Graf     machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0);
144d1b93565SAlexander Graf     if (machine_opts) {
145d1b93565SAlexander Graf         dtb_file = qemu_opt_get(machine_opts, "dtb");
146e6eaabebSScott Wood         toplevel_compat = qemu_opt_get(machine_opts, "dt_compatible");
147d1b93565SAlexander Graf     }
148d1b93565SAlexander Graf 
149d1b93565SAlexander Graf     if (dtb_file) {
150d1b93565SAlexander Graf         char *filename;
151d1b93565SAlexander Graf         filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_file);
152d1b93565SAlexander Graf         if (!filename) {
153d1b93565SAlexander Graf             goto out;
154d1b93565SAlexander Graf         }
155d1b93565SAlexander Graf 
156d1b93565SAlexander Graf         fdt = load_device_tree(filename, &fdt_size);
157d1b93565SAlexander Graf         if (!fdt) {
158d1b93565SAlexander Graf             goto out;
159d1b93565SAlexander Graf         }
160d1b93565SAlexander Graf         goto done;
161d1b93565SAlexander Graf     }
1621db09b84Saurel32 
1632636fcb6SAlexander Graf     fdt = create_device_tree(&fdt_size);
1645cea8590SPaul Brook     if (fdt == NULL) {
1655cea8590SPaul Brook         goto out;
1665cea8590SPaul Brook     }
1671db09b84Saurel32 
1681db09b84Saurel32     /* Manipulate device tree in memory. */
1693627757eSAlexander Graf     qemu_devtree_setprop_cell(fdt, "/", "#address-cells", 2);
1703627757eSAlexander Graf     qemu_devtree_setprop_cell(fdt, "/", "#size-cells", 2);
17151b852b7SAlexander Graf 
172dd0bcfcaSAlexander Graf     qemu_devtree_add_subnode(fdt, "/memory");
173dd0bcfcaSAlexander Graf     qemu_devtree_setprop_string(fdt, "/memory", "device_type", "memory");
174dd0bcfcaSAlexander Graf     qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property,
1751db09b84Saurel32                          sizeof(mem_reg_property));
1761db09b84Saurel32 
177f5231aafSAlexander Graf     qemu_devtree_add_subnode(fdt, "/chosen");
1783b989d49SAlexander Graf     if (initrd_size) {
1791db09b84Saurel32         ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start",
1801db09b84Saurel32                                         initrd_base);
1813b989d49SAlexander Graf         if (ret < 0) {
1821db09b84Saurel32             fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
1833b989d49SAlexander Graf         }
1841db09b84Saurel32 
1851db09b84Saurel32         ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end",
1861db09b84Saurel32                                         (initrd_base + initrd_size));
1873b989d49SAlexander Graf         if (ret < 0) {
1881db09b84Saurel32             fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
1893b989d49SAlexander Graf         }
1903b989d49SAlexander Graf     }
1911db09b84Saurel32 
1921db09b84Saurel32     ret = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs",
193e6eaabebSScott Wood                                       params->kernel_cmdline);
1941db09b84Saurel32     if (ret < 0)
1951db09b84Saurel32         fprintf(stderr, "couldn't set /chosen/bootargs\n");
1961db09b84Saurel32 
1971db09b84Saurel32     if (kvm_enabled()) {
198911d6e7aSAlexander Graf         /* Read out host's frequencies */
199911d6e7aSAlexander Graf         clock_freq = kvmppc_get_clockfreq();
200911d6e7aSAlexander Graf         tb_freq = kvmppc_get_tbfreq();
2015de6b46dSAlexander Graf 
2025de6b46dSAlexander Graf         /* indicate KVM hypercall interface */
203d50f71a5SAlexander Graf         qemu_devtree_add_subnode(fdt, "/hypervisor");
2045de6b46dSAlexander Graf         qemu_devtree_setprop_string(fdt, "/hypervisor", "compatible",
2055de6b46dSAlexander Graf                                     "linux,kvm");
2065de6b46dSAlexander Graf         kvmppc_get_hypercall(env, hypercall, sizeof(hypercall));
2075de6b46dSAlexander Graf         qemu_devtree_setprop(fdt, "/hypervisor", "hcall-instructions",
2085de6b46dSAlexander Graf                              hypercall, sizeof(hypercall));
2091db09b84Saurel32     }
2101db09b84Saurel32 
211625e665bSAlexander Graf     /* Create CPU nodes */
212625e665bSAlexander Graf     qemu_devtree_add_subnode(fdt, "/cpus");
213625e665bSAlexander Graf     qemu_devtree_setprop_cell(fdt, "/cpus", "#address-cells", 1);
214625e665bSAlexander Graf     qemu_devtree_setprop_cell(fdt, "/cpus", "#size-cells", 0);
215625e665bSAlexander Graf 
2161e3debf0SAlexander Graf     /* We need to generate the cpu nodes in reverse order, so Linux can pick
2171e3debf0SAlexander Graf        the first node as boot node and be happy */
2181e3debf0SAlexander Graf     for (i = smp_cpus - 1; i >= 0; i--) {
219621d05e3SAlexander Graf         char cpu_name[128];
2201d2e5c52SAlexander Graf         uint64_t cpu_release_addr = MPC8544_SPIN_BASE + (i * 0x20);
22110f25a46SAlexander Graf 
2221e3debf0SAlexander Graf         for (env = first_cpu; env != NULL; env = env->next_cpu) {
2231e3debf0SAlexander Graf             if (env->cpu_index == i) {
2241e3debf0SAlexander Graf                 break;
2251e3debf0SAlexander Graf             }
226621d05e3SAlexander Graf         }
227911d6e7aSAlexander Graf 
2281e3debf0SAlexander Graf         if (!env) {
2291e3debf0SAlexander Graf             continue;
2301e3debf0SAlexander Graf         }
2311e3debf0SAlexander Graf 
2321e3debf0SAlexander Graf         snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x", env->cpu_index);
2331e3debf0SAlexander Graf         qemu_devtree_add_subnode(fdt, cpu_name);
2341e3debf0SAlexander Graf         qemu_devtree_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq);
2351e3debf0SAlexander Graf         qemu_devtree_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq);
2361e3debf0SAlexander Graf         qemu_devtree_setprop_string(fdt, cpu_name, "device_type", "cpu");
2371e3debf0SAlexander Graf         qemu_devtree_setprop_cell(fdt, cpu_name, "reg", env->cpu_index);
2381e3debf0SAlexander Graf         qemu_devtree_setprop_cell(fdt, cpu_name, "d-cache-line-size",
2391e3debf0SAlexander Graf                                   env->dcache_line_size);
2401e3debf0SAlexander Graf         qemu_devtree_setprop_cell(fdt, cpu_name, "i-cache-line-size",
2411e3debf0SAlexander Graf                                   env->icache_line_size);
2421e3debf0SAlexander Graf         qemu_devtree_setprop_cell(fdt, cpu_name, "d-cache-size", 0x8000);
2431e3debf0SAlexander Graf         qemu_devtree_setprop_cell(fdt, cpu_name, "i-cache-size", 0x8000);
2441e3debf0SAlexander Graf         qemu_devtree_setprop_cell(fdt, cpu_name, "bus-frequency", 0);
2451e3debf0SAlexander Graf         if (env->cpu_index) {
2461e3debf0SAlexander Graf             qemu_devtree_setprop_string(fdt, cpu_name, "status", "disabled");
2471e3debf0SAlexander Graf             qemu_devtree_setprop_string(fdt, cpu_name, "enable-method", "spin-table");
2481d2e5c52SAlexander Graf             qemu_devtree_setprop_u64(fdt, cpu_name, "cpu-release-addr",
2491d2e5c52SAlexander Graf                                      cpu_release_addr);
2501e3debf0SAlexander Graf         } else {
2511e3debf0SAlexander Graf             qemu_devtree_setprop_string(fdt, cpu_name, "status", "okay");
2521e3debf0SAlexander Graf         }
2531db09b84Saurel32     }
2541db09b84Saurel32 
2550cfc6e8dSAlexander Graf     qemu_devtree_add_subnode(fdt, "/aliases");
2565da96624SAlexander Graf     /* XXX These should go into their respective devices' code */
257ed2bc496SAlexander Graf     snprintf(soc, sizeof(soc), "/soc@%llx", MPC8544_CCSRBAR_BASE);
2585da96624SAlexander Graf     qemu_devtree_add_subnode(fdt, soc);
2595da96624SAlexander Graf     qemu_devtree_setprop_string(fdt, soc, "device_type", "soc");
260ebb9518aSAlexander Graf     qemu_devtree_setprop(fdt, soc, "compatible", compatible_sb,
261ebb9518aSAlexander Graf                          sizeof(compatible_sb));
2625da96624SAlexander Graf     qemu_devtree_setprop_cell(fdt, soc, "#address-cells", 1);
2635da96624SAlexander Graf     qemu_devtree_setprop_cell(fdt, soc, "#size-cells", 1);
2643627757eSAlexander Graf     qemu_devtree_setprop_cells(fdt, soc, "ranges", 0x0,
2653627757eSAlexander Graf                                MPC8544_CCSRBAR_BASE >> 32, MPC8544_CCSRBAR_BASE,
2665da96624SAlexander Graf                                MPC8544_CCSRBAR_SIZE);
2675da96624SAlexander Graf     /* XXX should contain a reasonable value */
2685da96624SAlexander Graf     qemu_devtree_setprop_cell(fdt, soc, "bus-frequency", 0);
2695da96624SAlexander Graf 
270ed2bc496SAlexander Graf     snprintf(mpic, sizeof(mpic), "%s/pic@%llx", soc,
27119ac9deaSAlexander Graf              MPC8544_MPIC_REGS_BASE - MPC8544_CCSRBAR_BASE);
27219ac9deaSAlexander Graf     qemu_devtree_add_subnode(fdt, mpic);
27319ac9deaSAlexander Graf     qemu_devtree_setprop_string(fdt, mpic, "device_type", "open-pic");
2747e99826cSAlexander Graf     qemu_devtree_setprop_string(fdt, mpic, "compatible", "chrp,open-pic");
27519ac9deaSAlexander Graf     qemu_devtree_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_BASE -
27619ac9deaSAlexander Graf                                MPC8544_CCSRBAR_BASE, 0x40000);
27719ac9deaSAlexander Graf     qemu_devtree_setprop_cell(fdt, mpic, "#address-cells", 0);
2787e99826cSAlexander Graf     qemu_devtree_setprop_cell(fdt, mpic, "#interrupt-cells", 2);
27919ac9deaSAlexander Graf     mpic_ph = qemu_devtree_alloc_phandle(fdt);
28019ac9deaSAlexander Graf     qemu_devtree_setprop_cell(fdt, mpic, "phandle", mpic_ph);
28119ac9deaSAlexander Graf     qemu_devtree_setprop_cell(fdt, mpic, "linux,phandle", mpic_ph);
28219ac9deaSAlexander Graf     qemu_devtree_setprop(fdt, mpic, "interrupt-controller", NULL, 0);
28319ac9deaSAlexander Graf 
2840cfc6e8dSAlexander Graf     /*
2850cfc6e8dSAlexander Graf      * We have to generate ser1 first, because Linux takes the first
2860cfc6e8dSAlexander Graf      * device it finds in the dt as serial output device. And we generate
2870cfc6e8dSAlexander Graf      * devices in reverse order to the dt.
2880cfc6e8dSAlexander Graf      */
289a053a7ceSAlexander Graf     dt_serial_create(fdt, MPC8544_SERIAL1_REGS_BASE - MPC8544_CCSRBAR_BASE,
290a053a7ceSAlexander Graf                      soc, mpic, "serial1", 1, false);
291a053a7ceSAlexander Graf     dt_serial_create(fdt, MPC8544_SERIAL0_REGS_BASE - MPC8544_CCSRBAR_BASE,
292a053a7ceSAlexander Graf                      soc, mpic, "serial0", 0, true);
2930cfc6e8dSAlexander Graf 
294ed2bc496SAlexander Graf     snprintf(gutil, sizeof(gutil), "%s/global-utilities@%llx", soc,
295f5038483SAlexander Graf              MPC8544_UTIL_BASE - MPC8544_CCSRBAR_BASE);
296f5038483SAlexander Graf     qemu_devtree_add_subnode(fdt, gutil);
297f5038483SAlexander Graf     qemu_devtree_setprop_string(fdt, gutil, "compatible", "fsl,mpc8544-guts");
298f5038483SAlexander Graf     qemu_devtree_setprop_cells(fdt, gutil, "reg", MPC8544_UTIL_BASE -
299f5038483SAlexander Graf                                MPC8544_CCSRBAR_BASE, 0x1000);
300f5038483SAlexander Graf     qemu_devtree_setprop(fdt, gutil, "fsl,has-rstcr", NULL, 0);
301f5038483SAlexander Graf 
302ed2bc496SAlexander Graf     snprintf(pci, sizeof(pci), "/pci@%llx", MPC8544_PCI_REGS_BASE);
3030dbc0798SAlexander Graf     qemu_devtree_add_subnode(fdt, pci);
3040dbc0798SAlexander Graf     qemu_devtree_setprop_cell(fdt, pci, "cell-index", 0);
3050dbc0798SAlexander Graf     qemu_devtree_setprop_string(fdt, pci, "compatible", "fsl,mpc8540-pci");
3060dbc0798SAlexander Graf     qemu_devtree_setprop_string(fdt, pci, "device_type", "pci");
3070dbc0798SAlexander Graf     qemu_devtree_setprop_cells(fdt, pci, "interrupt-map-mask", 0xf800, 0x0,
3080dbc0798SAlexander Graf                                0x0, 0x7);
3090dbc0798SAlexander Graf     pci_map_create(fdt, pci_map, qemu_devtree_get_phandle(fdt, mpic));
3100dbc0798SAlexander Graf     qemu_devtree_setprop(fdt, pci, "interrupt-map", pci_map, sizeof(pci_map));
3110dbc0798SAlexander Graf     qemu_devtree_setprop_phandle(fdt, pci, "interrupt-parent", mpic);
3127e99826cSAlexander Graf     qemu_devtree_setprop_cells(fdt, pci, "interrupts", 24, 2);
3130dbc0798SAlexander Graf     qemu_devtree_setprop_cells(fdt, pci, "bus-range", 0, 255);
3143627757eSAlexander Graf     for (i = 0; i < 14; i++) {
3150dbc0798SAlexander Graf         pci_ranges[i] = cpu_to_be32(pci_ranges[i]);
3160dbc0798SAlexander Graf     }
3170dbc0798SAlexander Graf     qemu_devtree_setprop(fdt, pci, "ranges", pci_ranges, sizeof(pci_ranges));
3183627757eSAlexander Graf     qemu_devtree_setprop_cells(fdt, pci, "reg", MPC8544_PCI_REGS_BASE >> 32,
3193627757eSAlexander Graf                                MPC8544_PCI_REGS_BASE, 0, 0x1000);
3200dbc0798SAlexander Graf     qemu_devtree_setprop_cell(fdt, pci, "clock-frequency", 66666666);
3210dbc0798SAlexander Graf     qemu_devtree_setprop_cell(fdt, pci, "#interrupt-cells", 1);
3220dbc0798SAlexander Graf     qemu_devtree_setprop_cell(fdt, pci, "#size-cells", 2);
3230dbc0798SAlexander Graf     qemu_devtree_setprop_cell(fdt, pci, "#address-cells", 3);
3240dbc0798SAlexander Graf     qemu_devtree_setprop_string(fdt, "/aliases", "pci0", pci);
3250dbc0798SAlexander Graf 
326e6eaabebSScott Wood     params->fixup_devtree(params, fdt);
327e6eaabebSScott Wood 
328e6eaabebSScott Wood     if (toplevel_compat) {
329e6eaabebSScott Wood         qemu_devtree_setprop(fdt, "/", "compatible", toplevel_compat,
330e6eaabebSScott Wood                              strlen(toplevel_compat) + 1);
331e6eaabebSScott Wood     }
332e6eaabebSScott Wood 
333d1b93565SAlexander Graf done:
33471193433SAlexander Graf     qemu_devtree_dumpdtb(fdt, fdt_size);
33504088adbSLiu Yu     ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
336cba2026aSAlexander Graf     if (ret < 0) {
337cba2026aSAlexander Graf         goto out;
338cba2026aSAlexander Graf     }
3397267c094SAnthony Liguori     g_free(fdt);
340cba2026aSAlexander Graf     ret = fdt_size;
3417ec632b4Spbrook 
3421db09b84Saurel32 out:
3431db09b84Saurel32 
34404088adbSLiu Yu     return ret;
3451db09b84Saurel32 }
3461db09b84Saurel32 
347cba2026aSAlexander Graf /* Create -kernel TLB entries for BookE.  */
348a8170e5eSAvi Kivity static inline hwaddr booke206_page_size_to_tlb(uint64_t size)
349d1e256feSAlexander Graf {
350cba2026aSAlexander Graf     return 63 - clz64(size >> 10);
351d1e256feSAlexander Graf }
352d1e256feSAlexander Graf 
353cba2026aSAlexander Graf static void mmubooke_create_initial_mapping(CPUPPCState *env)
3543b989d49SAlexander Graf {
355cba2026aSAlexander Graf     struct boot_info *bi = env->load_info;
356d1e256feSAlexander Graf     ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0);
357a8170e5eSAvi Kivity     hwaddr size, dt_end;
358cba2026aSAlexander Graf     int ps;
3593b989d49SAlexander Graf 
360cba2026aSAlexander Graf     /* Our initial TLB entry needs to cover everything from 0 to
361cba2026aSAlexander Graf        the device tree top */
362cba2026aSAlexander Graf     dt_end = bi->dt_base + bi->dt_size;
363cba2026aSAlexander Graf     ps = booke206_page_size_to_tlb(dt_end) + 1;
364fb37c302SAlexander Graf     if (ps & 1) {
365fb37c302SAlexander Graf         /* e500v2 can only do even TLB size bits */
366fb37c302SAlexander Graf         ps++;
367fb37c302SAlexander Graf     }
368cba2026aSAlexander Graf     size = (ps << MAS1_TSIZE_SHIFT);
369d1e256feSAlexander Graf     tlb->mas1 = MAS1_VALID | size;
370cba2026aSAlexander Graf     tlb->mas2 = 0;
371cba2026aSAlexander Graf     tlb->mas7_3 = 0;
372d1e256feSAlexander Graf     tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
37393dd5e85SScott Wood 
37493dd5e85SScott Wood     env->tlb_dirty = true;
3753b989d49SAlexander Graf }
3763b989d49SAlexander Graf 
377b3305981SScott Wood static void ppce500_cpu_reset_sec(void *opaque)
3785c145dacSAlexander Graf {
37938f92da6SAndreas Färber     PowerPCCPU *cpu = opaque;
38038f92da6SAndreas Färber     CPUPPCState *env = &cpu->env;
3815c145dacSAlexander Graf 
38238f92da6SAndreas Färber     cpu_reset(CPU(cpu));
3835c145dacSAlexander Graf 
3845c145dacSAlexander Graf     /* Secondary CPU starts in halted state for now. Needs to change when
3855c145dacSAlexander Graf        implementing non-kernel boot. */
3865c145dacSAlexander Graf     env->halted = 1;
3875c145dacSAlexander Graf     env->exception_index = EXCP_HLT;
3883b989d49SAlexander Graf }
3893b989d49SAlexander Graf 
390b3305981SScott Wood static void ppce500_cpu_reset(void *opaque)
3913b989d49SAlexander Graf {
39238f92da6SAndreas Färber     PowerPCCPU *cpu = opaque;
39338f92da6SAndreas Färber     CPUPPCState *env = &cpu->env;
3943b989d49SAlexander Graf     struct boot_info *bi = env->load_info;
3953b989d49SAlexander Graf 
39638f92da6SAndreas Färber     cpu_reset(CPU(cpu));
3973b989d49SAlexander Graf 
3983b989d49SAlexander Graf     /* Set initial guest state. */
3995c145dacSAlexander Graf     env->halted = 0;
4003b989d49SAlexander Graf     env->gpr[1] = (16<<20) - 8;
4013b989d49SAlexander Graf     env->gpr[3] = bi->dt_base;
4023b989d49SAlexander Graf     env->nip = bi->entry;
403cba2026aSAlexander Graf     mmubooke_create_initial_mapping(env);
4043b989d49SAlexander Graf }
4053b989d49SAlexander Graf 
406e6eaabebSScott Wood void ppce500_init(PPCE500Params *params)
4071db09b84Saurel32 {
40839186d8aSRichard Henderson     MemoryRegion *address_space_mem = get_system_memory();
4092646c133SAvi Kivity     MemoryRegion *ram = g_new(MemoryRegion, 1);
4101db09b84Saurel32     PCIBus *pci_bus;
411e2684c0bSAndreas Färber     CPUPPCState *env = NULL;
4121db09b84Saurel32     uint64_t elf_entry;
4131db09b84Saurel32     uint64_t elf_lowaddr;
414a8170e5eSAvi Kivity     hwaddr entry=0;
415a8170e5eSAvi Kivity     hwaddr loadaddr=UIMAGE_LOAD_BASE;
4161db09b84Saurel32     target_long kernel_size=0;
41775bb6589SLiu Yu     target_ulong dt_base = 0;
41875bb6589SLiu Yu     target_ulong initrd_base = 0;
4191db09b84Saurel32     target_long initrd_size=0;
4201db09b84Saurel32     int i=0;
4211db09b84Saurel32     unsigned int pci_irq_nrs[4] = {1, 2, 3, 4};
422a915249fSAlexander Graf     qemu_irq **irqs, *mpic;
423be13cc7aSAlexander Graf     DeviceState *dev;
424e2684c0bSAndreas Färber     CPUPPCState *firstenv = NULL;
4251db09b84Saurel32 
426e61c36d5SAlexander Graf     /* Setup CPUs */
427e6eaabebSScott Wood     if (params->cpu_model == NULL) {
428e6eaabebSScott Wood         params->cpu_model = "e500v2_v30";
429ef250db6SAlexander Graf     }
430ef250db6SAlexander Graf 
431a915249fSAlexander Graf     irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *));
432a915249fSAlexander Graf     irqs[0] = g_malloc0(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
433e61c36d5SAlexander Graf     for (i = 0; i < smp_cpus; i++) {
434397b457dSAndreas Färber         PowerPCCPU *cpu;
435e61c36d5SAlexander Graf         qemu_irq *input;
436397b457dSAndreas Färber 
437e6eaabebSScott Wood         cpu = cpu_ppc_init(params->cpu_model);
438397b457dSAndreas Färber         if (cpu == NULL) {
4391db09b84Saurel32             fprintf(stderr, "Unable to initialize CPU!\n");
4401db09b84Saurel32             exit(1);
4411db09b84Saurel32         }
442397b457dSAndreas Färber         env = &cpu->env;
4431db09b84Saurel32 
444e61c36d5SAlexander Graf         if (!firstenv) {
445e61c36d5SAlexander Graf             firstenv = env;
446e61c36d5SAlexander Graf         }
447e61c36d5SAlexander Graf 
448a915249fSAlexander Graf         irqs[i] = irqs[0] + (i * OPENPIC_OUTPUT_NB);
449a915249fSAlexander Graf         input = (qemu_irq *)env->irq_inputs;
450a915249fSAlexander Graf         irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT];
451a915249fSAlexander Graf         irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT];
452e61c36d5SAlexander Graf         env->spr[SPR_BOOKE_PIR] = env->cpu_index = i;
4532a7a47fcSAlexander Graf         env->mpic_cpu_base = MPC8544_MPIC_REGS_BASE + 0x20000;
454e61c36d5SAlexander Graf 
455ddd1055bSFabien Chouteau         ppc_booke_timers_init(env, 400000000, PPC_TIMER_E500);
4563b989d49SAlexander Graf 
4573b989d49SAlexander Graf         /* Register reset handler */
4585c145dacSAlexander Graf         if (!i) {
4595c145dacSAlexander Graf             /* Primary CPU */
4605c145dacSAlexander Graf             struct boot_info *boot_info;
461e61c36d5SAlexander Graf             boot_info = g_malloc0(sizeof(struct boot_info));
462b3305981SScott Wood             qemu_register_reset(ppce500_cpu_reset, cpu);
463e61c36d5SAlexander Graf             env->load_info = boot_info;
4645c145dacSAlexander Graf         } else {
4655c145dacSAlexander Graf             /* Secondary CPUs */
466b3305981SScott Wood             qemu_register_reset(ppce500_cpu_reset_sec, cpu);
4675c145dacSAlexander Graf         }
468e61c36d5SAlexander Graf     }
469e61c36d5SAlexander Graf 
470e61c36d5SAlexander Graf     env = firstenv;
4713b989d49SAlexander Graf 
4721db09b84Saurel32     /* Fixup Memory size on a alignment boundary */
4731db09b84Saurel32     ram_size &= ~(RAM_SIZES_ALIGN - 1);
4741db09b84Saurel32 
4751db09b84Saurel32     /* Register Memory */
476c5705a77SAvi Kivity     memory_region_init_ram(ram, "mpc8544ds.ram", ram_size);
477c5705a77SAvi Kivity     vmstate_register_ram_global(ram);
4782646c133SAvi Kivity     memory_region_add_subregion(address_space_mem, 0, ram);
4791db09b84Saurel32 
4801db09b84Saurel32     /* MPIC */
481df2921d3SAvi Kivity     mpic = mpic_init(address_space_mem, MPC8544_MPIC_REGS_BASE,
482df2921d3SAvi Kivity                      smp_cpus, irqs, NULL);
483a915249fSAlexander Graf 
484a915249fSAlexander Graf     if (!mpic) {
485a915249fSAlexander Graf         cpu_abort(env, "MPIC failed to initialize\n");
486a915249fSAlexander Graf     }
4871db09b84Saurel32 
4881db09b84Saurel32     /* Serial */
4892d48377aSBlue Swirl     if (serial_hds[0]) {
49039186d8aSRichard Henderson         serial_mm_init(address_space_mem, MPC8544_SERIAL0_REGS_BASE,
4911db09b84Saurel32                        0, mpic[12+26], 399193,
4922ff0c7c3SRichard Henderson                        serial_hds[0], DEVICE_BIG_ENDIAN);
4932d48377aSBlue Swirl     }
4941db09b84Saurel32 
4952d48377aSBlue Swirl     if (serial_hds[1]) {
49639186d8aSRichard Henderson         serial_mm_init(address_space_mem, MPC8544_SERIAL1_REGS_BASE,
4971db09b84Saurel32                        0, mpic[12+26], 399193,
49859de4f98SBharat Bhushan                        serial_hds[1], DEVICE_BIG_ENDIAN);
4992d48377aSBlue Swirl     }
5001db09b84Saurel32 
501b0fb8423SAlexander Graf     /* General Utility device */
502b0fb8423SAlexander Graf     sysbus_create_simple("mpc8544-guts", MPC8544_UTIL_BASE, NULL);
503b0fb8423SAlexander Graf 
5041db09b84Saurel32     /* PCI */
505be13cc7aSAlexander Graf     dev = sysbus_create_varargs("e500-pcihost", MPC8544_PCI_REGS_BASE,
506be13cc7aSAlexander Graf                                 mpic[pci_irq_nrs[0]], mpic[pci_irq_nrs[1]],
507be13cc7aSAlexander Graf                                 mpic[pci_irq_nrs[2]], mpic[pci_irq_nrs[3]],
508be13cc7aSAlexander Graf                                 NULL);
509d461e3b9SAlexander Graf     pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
5101db09b84Saurel32     if (!pci_bus)
5111db09b84Saurel32         printf("couldn't create PCI controller!\n");
5121db09b84Saurel32 
513*a1bc20dfSAlexander Graf     sysbus_mmio_map(sysbus_from_qdev(dev), 1, MPC8544_PCI_IO);
5141db09b84Saurel32 
5151db09b84Saurel32     if (pci_bus) {
5161db09b84Saurel32         /* Register network interfaces. */
5171db09b84Saurel32         for (i = 0; i < nb_nics; i++) {
51807caea31SMarkus Armbruster             pci_nic_init_nofail(&nd_table[i], "virtio", NULL);
5191db09b84Saurel32         }
5201db09b84Saurel32     }
5211db09b84Saurel32 
5225c145dacSAlexander Graf     /* Register spinning region */
5235c145dacSAlexander Graf     sysbus_create_simple("e500-spin", MPC8544_SPIN_BASE, NULL);
5245c145dacSAlexander Graf 
5251db09b84Saurel32     /* Load kernel. */
526e6eaabebSScott Wood     if (params->kernel_filename) {
527e6eaabebSScott Wood         kernel_size = load_uimage(params->kernel_filename, &entry,
528e6eaabebSScott Wood                                   &loadaddr, NULL);
5291db09b84Saurel32         if (kernel_size < 0) {
530e6eaabebSScott Wood             kernel_size = load_elf(params->kernel_filename, NULL, NULL,
531e6eaabebSScott Wood                                    &elf_entry, &elf_lowaddr, NULL, 1,
532e6eaabebSScott Wood                                    ELF_MACHINE, 0);
5331db09b84Saurel32             entry = elf_entry;
5341db09b84Saurel32             loadaddr = elf_lowaddr;
5351db09b84Saurel32         }
5361db09b84Saurel32         /* XXX try again as binary */
5371db09b84Saurel32         if (kernel_size < 0) {
5381db09b84Saurel32             fprintf(stderr, "qemu: could not load kernel '%s'\n",
539e6eaabebSScott Wood                     params->kernel_filename);
5401db09b84Saurel32             exit(1);
5411db09b84Saurel32         }
5421db09b84Saurel32     }
5431db09b84Saurel32 
5441db09b84Saurel32     /* Load initrd. */
545e6eaabebSScott Wood     if (params->initrd_filename) {
5467e7ec2d2SScott Wood         initrd_base = (loadaddr + kernel_size + INITRD_LOAD_PAD) &
5477e7ec2d2SScott Wood             ~INITRD_PAD_MASK;
548e6eaabebSScott Wood         initrd_size = load_image_targphys(params->initrd_filename, initrd_base,
549d7585251Spbrook                                           ram_size - initrd_base);
5501db09b84Saurel32 
5511db09b84Saurel32         if (initrd_size < 0) {
5521db09b84Saurel32             fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
553e6eaabebSScott Wood                     params->initrd_filename);
5541db09b84Saurel32             exit(1);
5551db09b84Saurel32         }
5561db09b84Saurel32     }
5571db09b84Saurel32 
5581db09b84Saurel32     /* If we're loading a kernel directly, we must load the device tree too. */
559e6eaabebSScott Wood     if (params->kernel_filename) {
5605c145dacSAlexander Graf         struct boot_info *boot_info;
561cba2026aSAlexander Graf         int dt_size;
5625c145dacSAlexander Graf 
563cba2026aSAlexander Graf         dt_base = (loadaddr + kernel_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
564e6eaabebSScott Wood         dt_size = ppce500_load_device_tree(env, params, dt_base, initrd_base,
565e6eaabebSScott Wood                                            initrd_size);
566cba2026aSAlexander Graf         if (dt_size < 0) {
5671db09b84Saurel32             fprintf(stderr, "couldn't load device tree\n");
5681db09b84Saurel32             exit(1);
5691db09b84Saurel32         }
5701db09b84Saurel32 
571e61c36d5SAlexander Graf         boot_info = env->load_info;
5723b989d49SAlexander Graf         boot_info->entry = entry;
5733b989d49SAlexander Graf         boot_info->dt_base = dt_base;
574cba2026aSAlexander Graf         boot_info->dt_size = dt_size;
5751db09b84Saurel32     }
5761db09b84Saurel32 
5773b989d49SAlexander Graf     if (kvm_enabled()) {
5781db09b84Saurel32         kvmppc_init();
5793b989d49SAlexander Graf     }
5801db09b84Saurel32 }
581