xref: /qemu/hw/ppc/e500.c (revision 3eddc1be1ccb26387f8f960f8a3d8c417064a91f)
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"
20*3eddc1beSBharat Bhushan #include "e500-ccsr.h"
211db09b84Saurel32 #include "net.h"
224a18e7c9SScott Wood #include "hw/hw.h"
23488cb996SGerd Hoffmann #include "hw/serial.h"
244a18e7c9SScott Wood #include "hw/pci.h"
254a18e7c9SScott Wood #include "hw/boards.h"
261db09b84Saurel32 #include "sysemu.h"
271db09b84Saurel32 #include "kvm.h"
281db09b84Saurel32 #include "kvm_ppc.h"
291db09b84Saurel32 #include "device_tree.h"
304a18e7c9SScott Wood #include "hw/openpic.h"
314a18e7c9SScott Wood #include "hw/ppc.h"
324a18e7c9SScott Wood #include "hw/loader.h"
33ca20cf32SBlue Swirl #include "elf.h"
344a18e7c9SScott Wood #include "hw/sysbus.h"
3539186d8aSRichard Henderson #include "exec-memory.h"
36cba2026aSAlexander Graf #include "host-utils.h"
371db09b84Saurel32 
381db09b84Saurel32 #define BINARY_DEVICE_TREE_FILE    "mpc8544ds.dtb"
391db09b84Saurel32 #define UIMAGE_LOAD_BASE           0
409dd5eba1SScott Wood #define DTC_LOAD_PAD               0x1800000
4175bb6589SLiu Yu #define DTC_PAD_MASK               0xFFFFF
4275bb6589SLiu Yu #define INITRD_LOAD_PAD            0x2000000
4375bb6589SLiu Yu #define INITRD_PAD_MASK            0xFFFFFF
441db09b84Saurel32 
451db09b84Saurel32 #define RAM_SIZES_ALIGN            (64UL << 20)
461db09b84Saurel32 
47b3305981SScott Wood /* TODO: parameterize */
48ed2bc496SAlexander Graf #define MPC8544_CCSRBAR_BASE       0xE0000000ULL
49ed2bc496SAlexander Graf #define MPC8544_CCSRBAR_SIZE       0x00100000ULL
50dffb1dc2SBharat Bhushan #define MPC8544_MPIC_REGS_OFFSET   0x40000ULL
51dffb1dc2SBharat Bhushan #define MPC8544_SERIAL0_REGS_OFFSET 0x4500ULL
52dffb1dc2SBharat Bhushan #define MPC8544_SERIAL1_REGS_OFFSET 0x4600ULL
53dffb1dc2SBharat Bhushan #define MPC8544_PCI_REGS_OFFSET    0x8000ULL
54dffb1dc2SBharat Bhushan #define MPC8544_PCI_REGS_BASE      (MPC8544_CCSRBAR_BASE + \
55dffb1dc2SBharat Bhushan                                     MPC8544_PCI_REGS_OFFSET)
56ed2bc496SAlexander Graf #define MPC8544_PCI_REGS_SIZE      0x1000ULL
57ed2bc496SAlexander Graf #define MPC8544_PCI_IO             0xE1000000ULL
58dffb1dc2SBharat Bhushan #define MPC8544_UTIL_OFFSET        0xe0000ULL
59ed2bc496SAlexander Graf #define MPC8544_SPIN_BASE          0xEF000000ULL
601db09b84Saurel32 
613b989d49SAlexander Graf struct boot_info
623b989d49SAlexander Graf {
633b989d49SAlexander Graf     uint32_t dt_base;
64cba2026aSAlexander Graf     uint32_t dt_size;
653b989d49SAlexander Graf     uint32_t entry;
663b989d49SAlexander Graf };
673b989d49SAlexander Graf 
680dbc0798SAlexander Graf static void pci_map_create(void *fdt, uint32_t *pci_map, uint32_t mpic)
690dbc0798SAlexander Graf {
700dbc0798SAlexander Graf     int i;
710dbc0798SAlexander Graf     const uint32_t tmp[] = {
720dbc0798SAlexander Graf                              /* IDSEL 0x11 J17 Slot 1 */
737e99826cSAlexander Graf                              0x8800, 0x0, 0x0, 0x1, mpic, 0x2, 0x1,
747e99826cSAlexander Graf                              0x8800, 0x0, 0x0, 0x2, mpic, 0x3, 0x1,
757e99826cSAlexander Graf                              0x8800, 0x0, 0x0, 0x3, mpic, 0x4, 0x1,
767e99826cSAlexander Graf                              0x8800, 0x0, 0x0, 0x4, mpic, 0x1, 0x1,
770dbc0798SAlexander Graf 
780dbc0798SAlexander Graf                              /* IDSEL 0x12 J16 Slot 2 */
797e99826cSAlexander Graf                              0x9000, 0x0, 0x0, 0x1, mpic, 0x3, 0x1,
807e99826cSAlexander Graf                              0x9000, 0x0, 0x0, 0x2, mpic, 0x4, 0x1,
817e99826cSAlexander Graf                              0x9000, 0x0, 0x0, 0x3, mpic, 0x2, 0x1,
827e99826cSAlexander Graf                              0x9000, 0x0, 0x0, 0x4, mpic, 0x1, 0x1,
830dbc0798SAlexander Graf                            };
847e99826cSAlexander Graf     for (i = 0; i < (7 * 8); i++) {
850dbc0798SAlexander Graf         pci_map[i] = cpu_to_be32(tmp[i]);
860dbc0798SAlexander Graf     }
870dbc0798SAlexander Graf }
880dbc0798SAlexander Graf 
89a053a7ceSAlexander Graf static void dt_serial_create(void *fdt, unsigned long long offset,
90a053a7ceSAlexander Graf                              const char *soc, const char *mpic,
91a053a7ceSAlexander Graf                              const char *alias, int idx, bool defcon)
92a053a7ceSAlexander Graf {
93a053a7ceSAlexander Graf     char ser[128];
94a053a7ceSAlexander Graf 
95a053a7ceSAlexander Graf     snprintf(ser, sizeof(ser), "%s/serial@%llx", soc, offset);
96a053a7ceSAlexander Graf     qemu_devtree_add_subnode(fdt, ser);
97a053a7ceSAlexander Graf     qemu_devtree_setprop_string(fdt, ser, "device_type", "serial");
98a053a7ceSAlexander Graf     qemu_devtree_setprop_string(fdt, ser, "compatible", "ns16550");
99a053a7ceSAlexander Graf     qemu_devtree_setprop_cells(fdt, ser, "reg", offset, 0x100);
100a053a7ceSAlexander Graf     qemu_devtree_setprop_cell(fdt, ser, "cell-index", idx);
101a053a7ceSAlexander Graf     qemu_devtree_setprop_cell(fdt, ser, "clock-frequency", 0);
1027e99826cSAlexander Graf     qemu_devtree_setprop_cells(fdt, ser, "interrupts", 42, 2);
103a053a7ceSAlexander Graf     qemu_devtree_setprop_phandle(fdt, ser, "interrupt-parent", mpic);
104a053a7ceSAlexander Graf     qemu_devtree_setprop_string(fdt, "/aliases", alias, ser);
105a053a7ceSAlexander Graf 
106a053a7ceSAlexander Graf     if (defcon) {
107a053a7ceSAlexander Graf         qemu_devtree_setprop_string(fdt, "/chosen", "linux,stdout-path", ser);
108a053a7ceSAlexander Graf     }
109a053a7ceSAlexander Graf }
110a053a7ceSAlexander Graf 
111b3305981SScott Wood static int ppce500_load_device_tree(CPUPPCState *env,
112e6eaabebSScott Wood                                     PPCE500Params *params,
113a8170e5eSAvi Kivity                                     hwaddr addr,
114a8170e5eSAvi Kivity                                     hwaddr initrd_base,
115a8170e5eSAvi Kivity                                     hwaddr initrd_size)
1161db09b84Saurel32 {
117dbf916d8SAurelien Jarno     int ret = -1;
118e6eaabebSScott Wood     uint64_t mem_reg_property[] = { 0, cpu_to_be64(params->ram_size) };
1197ec632b4Spbrook     int fdt_size;
120dbf916d8SAurelien Jarno     void *fdt;
1215de6b46dSAlexander Graf     uint8_t hypercall[16];
122911d6e7aSAlexander Graf     uint32_t clock_freq = 400000000;
123911d6e7aSAlexander Graf     uint32_t tb_freq = 400000000;
124621d05e3SAlexander Graf     int i;
125e6eaabebSScott Wood     const char *toplevel_compat = NULL; /* user override */
126ebb9518aSAlexander Graf     char compatible_sb[] = "fsl,mpc8544-immr\0simple-bus";
1275da96624SAlexander Graf     char soc[128];
12819ac9deaSAlexander Graf     char mpic[128];
12919ac9deaSAlexander Graf     uint32_t mpic_ph;
130f5038483SAlexander Graf     char gutil[128];
1310dbc0798SAlexander Graf     char pci[128];
1327e99826cSAlexander Graf     uint32_t pci_map[7 * 8];
1333627757eSAlexander Graf     uint32_t pci_ranges[14] =
1343627757eSAlexander Graf         {
1353627757eSAlexander Graf             0x2000000, 0x0, 0xc0000000,
1363627757eSAlexander Graf             0x0, 0xc0000000,
1373627757eSAlexander Graf             0x0, 0x20000000,
1383627757eSAlexander Graf 
1393627757eSAlexander Graf             0x1000000, 0x0, 0x0,
1403627757eSAlexander Graf             0x0, 0xe1000000,
1413627757eSAlexander Graf             0x0, 0x10000,
1423627757eSAlexander Graf         };
14325b42708SAlexander Graf     QemuOpts *machine_opts;
144d1b93565SAlexander Graf     const char *dtb_file = NULL;
145d1b93565SAlexander Graf 
146d1b93565SAlexander Graf     machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0);
147d1b93565SAlexander Graf     if (machine_opts) {
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 
273dffb1dc2SBharat Bhushan     snprintf(mpic, sizeof(mpic), "%s/pic@%llx", soc, MPC8544_MPIC_REGS_OFFSET);
27419ac9deaSAlexander Graf     qemu_devtree_add_subnode(fdt, mpic);
27519ac9deaSAlexander Graf     qemu_devtree_setprop_string(fdt, mpic, "device_type", "open-pic");
2767e99826cSAlexander Graf     qemu_devtree_setprop_string(fdt, mpic, "compatible", "chrp,open-pic");
277dffb1dc2SBharat Bhushan     qemu_devtree_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_OFFSET,
278dffb1dc2SBharat Bhushan                                0x40000);
27919ac9deaSAlexander Graf     qemu_devtree_setprop_cell(fdt, mpic, "#address-cells", 0);
2807e99826cSAlexander Graf     qemu_devtree_setprop_cell(fdt, mpic, "#interrupt-cells", 2);
28119ac9deaSAlexander Graf     mpic_ph = qemu_devtree_alloc_phandle(fdt);
28219ac9deaSAlexander Graf     qemu_devtree_setprop_cell(fdt, mpic, "phandle", mpic_ph);
28319ac9deaSAlexander Graf     qemu_devtree_setprop_cell(fdt, mpic, "linux,phandle", mpic_ph);
28419ac9deaSAlexander Graf     qemu_devtree_setprop(fdt, mpic, "interrupt-controller", NULL, 0);
28519ac9deaSAlexander Graf 
2860cfc6e8dSAlexander Graf     /*
2870cfc6e8dSAlexander Graf      * We have to generate ser1 first, because Linux takes the first
2880cfc6e8dSAlexander Graf      * device it finds in the dt as serial output device. And we generate
2890cfc6e8dSAlexander Graf      * devices in reverse order to the dt.
2900cfc6e8dSAlexander Graf      */
291dffb1dc2SBharat Bhushan     dt_serial_create(fdt, MPC8544_SERIAL1_REGS_OFFSET,
292a053a7ceSAlexander Graf                      soc, mpic, "serial1", 1, false);
293dffb1dc2SBharat Bhushan     dt_serial_create(fdt, MPC8544_SERIAL0_REGS_OFFSET,
294a053a7ceSAlexander Graf                      soc, mpic, "serial0", 0, true);
2950cfc6e8dSAlexander Graf 
296ed2bc496SAlexander Graf     snprintf(gutil, sizeof(gutil), "%s/global-utilities@%llx", soc,
297dffb1dc2SBharat Bhushan              MPC8544_UTIL_OFFSET);
298f5038483SAlexander Graf     qemu_devtree_add_subnode(fdt, gutil);
299f5038483SAlexander Graf     qemu_devtree_setprop_string(fdt, gutil, "compatible", "fsl,mpc8544-guts");
300dffb1dc2SBharat Bhushan     qemu_devtree_setprop_cells(fdt, gutil, "reg", MPC8544_UTIL_OFFSET, 0x1000);
301f5038483SAlexander Graf     qemu_devtree_setprop(fdt, gutil, "fsl,has-rstcr", NULL, 0);
302f5038483SAlexander Graf 
303ed2bc496SAlexander Graf     snprintf(pci, sizeof(pci), "/pci@%llx", MPC8544_PCI_REGS_BASE);
3040dbc0798SAlexander Graf     qemu_devtree_add_subnode(fdt, pci);
3050dbc0798SAlexander Graf     qemu_devtree_setprop_cell(fdt, pci, "cell-index", 0);
3060dbc0798SAlexander Graf     qemu_devtree_setprop_string(fdt, pci, "compatible", "fsl,mpc8540-pci");
3070dbc0798SAlexander Graf     qemu_devtree_setprop_string(fdt, pci, "device_type", "pci");
3080dbc0798SAlexander Graf     qemu_devtree_setprop_cells(fdt, pci, "interrupt-map-mask", 0xf800, 0x0,
3090dbc0798SAlexander Graf                                0x0, 0x7);
3100dbc0798SAlexander Graf     pci_map_create(fdt, pci_map, qemu_devtree_get_phandle(fdt, mpic));
3110dbc0798SAlexander Graf     qemu_devtree_setprop(fdt, pci, "interrupt-map", pci_map, sizeof(pci_map));
3120dbc0798SAlexander Graf     qemu_devtree_setprop_phandle(fdt, pci, "interrupt-parent", mpic);
3137e99826cSAlexander Graf     qemu_devtree_setprop_cells(fdt, pci, "interrupts", 24, 2);
3140dbc0798SAlexander Graf     qemu_devtree_setprop_cells(fdt, pci, "bus-range", 0, 255);
3153627757eSAlexander Graf     for (i = 0; i < 14; i++) {
3160dbc0798SAlexander Graf         pci_ranges[i] = cpu_to_be32(pci_ranges[i]);
3170dbc0798SAlexander Graf     }
3180dbc0798SAlexander Graf     qemu_devtree_setprop(fdt, pci, "ranges", pci_ranges, sizeof(pci_ranges));
3193627757eSAlexander Graf     qemu_devtree_setprop_cells(fdt, pci, "reg", MPC8544_PCI_REGS_BASE >> 32,
3203627757eSAlexander Graf                                MPC8544_PCI_REGS_BASE, 0, 0x1000);
3210dbc0798SAlexander Graf     qemu_devtree_setprop_cell(fdt, pci, "clock-frequency", 66666666);
3220dbc0798SAlexander Graf     qemu_devtree_setprop_cell(fdt, pci, "#interrupt-cells", 1);
3230dbc0798SAlexander Graf     qemu_devtree_setprop_cell(fdt, pci, "#size-cells", 2);
3240dbc0798SAlexander Graf     qemu_devtree_setprop_cell(fdt, pci, "#address-cells", 3);
3250dbc0798SAlexander Graf     qemu_devtree_setprop_string(fdt, "/aliases", "pci0", pci);
3260dbc0798SAlexander Graf 
327e6eaabebSScott Wood     params->fixup_devtree(params, fdt);
328e6eaabebSScott Wood 
329e6eaabebSScott Wood     if (toplevel_compat) {
330e6eaabebSScott Wood         qemu_devtree_setprop(fdt, "/", "compatible", toplevel_compat,
331e6eaabebSScott Wood                              strlen(toplevel_compat) + 1);
332e6eaabebSScott Wood     }
333e6eaabebSScott Wood 
334d1b93565SAlexander Graf done:
33571193433SAlexander Graf     qemu_devtree_dumpdtb(fdt, fdt_size);
33604088adbSLiu Yu     ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
337cba2026aSAlexander Graf     if (ret < 0) {
338cba2026aSAlexander Graf         goto out;
339cba2026aSAlexander Graf     }
3407267c094SAnthony Liguori     g_free(fdt);
341cba2026aSAlexander Graf     ret = fdt_size;
3427ec632b4Spbrook 
3431db09b84Saurel32 out:
3441db09b84Saurel32 
34504088adbSLiu Yu     return ret;
3461db09b84Saurel32 }
3471db09b84Saurel32 
348cba2026aSAlexander Graf /* Create -kernel TLB entries for BookE.  */
349a8170e5eSAvi Kivity static inline hwaddr booke206_page_size_to_tlb(uint64_t size)
350d1e256feSAlexander Graf {
351cba2026aSAlexander Graf     return 63 - clz64(size >> 10);
352d1e256feSAlexander Graf }
353d1e256feSAlexander Graf 
354cba2026aSAlexander Graf static void mmubooke_create_initial_mapping(CPUPPCState *env)
3553b989d49SAlexander Graf {
356cba2026aSAlexander Graf     struct boot_info *bi = env->load_info;
357d1e256feSAlexander Graf     ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0);
358a8170e5eSAvi Kivity     hwaddr size, dt_end;
359cba2026aSAlexander Graf     int ps;
3603b989d49SAlexander Graf 
361cba2026aSAlexander Graf     /* Our initial TLB entry needs to cover everything from 0 to
362cba2026aSAlexander Graf        the device tree top */
363cba2026aSAlexander Graf     dt_end = bi->dt_base + bi->dt_size;
364cba2026aSAlexander Graf     ps = booke206_page_size_to_tlb(dt_end) + 1;
365fb37c302SAlexander Graf     if (ps & 1) {
366fb37c302SAlexander Graf         /* e500v2 can only do even TLB size bits */
367fb37c302SAlexander Graf         ps++;
368fb37c302SAlexander Graf     }
369cba2026aSAlexander Graf     size = (ps << MAS1_TSIZE_SHIFT);
370d1e256feSAlexander Graf     tlb->mas1 = MAS1_VALID | size;
371cba2026aSAlexander Graf     tlb->mas2 = 0;
372cba2026aSAlexander Graf     tlb->mas7_3 = 0;
373d1e256feSAlexander Graf     tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
37493dd5e85SScott Wood 
37593dd5e85SScott Wood     env->tlb_dirty = true;
3763b989d49SAlexander Graf }
3773b989d49SAlexander Graf 
378b3305981SScott Wood static void ppce500_cpu_reset_sec(void *opaque)
3795c145dacSAlexander Graf {
38038f92da6SAndreas Färber     PowerPCCPU *cpu = opaque;
38138f92da6SAndreas Färber     CPUPPCState *env = &cpu->env;
3825c145dacSAlexander Graf 
38338f92da6SAndreas Färber     cpu_reset(CPU(cpu));
3845c145dacSAlexander Graf 
3855c145dacSAlexander Graf     /* Secondary CPU starts in halted state for now. Needs to change when
3865c145dacSAlexander Graf        implementing non-kernel boot. */
3875c145dacSAlexander Graf     env->halted = 1;
3885c145dacSAlexander Graf     env->exception_index = EXCP_HLT;
3893b989d49SAlexander Graf }
3903b989d49SAlexander Graf 
391b3305981SScott Wood static void ppce500_cpu_reset(void *opaque)
3923b989d49SAlexander Graf {
39338f92da6SAndreas Färber     PowerPCCPU *cpu = opaque;
39438f92da6SAndreas Färber     CPUPPCState *env = &cpu->env;
3953b989d49SAlexander Graf     struct boot_info *bi = env->load_info;
3963b989d49SAlexander Graf 
39738f92da6SAndreas Färber     cpu_reset(CPU(cpu));
3983b989d49SAlexander Graf 
3993b989d49SAlexander Graf     /* Set initial guest state. */
4005c145dacSAlexander Graf     env->halted = 0;
4013b989d49SAlexander Graf     env->gpr[1] = (16<<20) - 8;
4023b989d49SAlexander Graf     env->gpr[3] = bi->dt_base;
4033b989d49SAlexander Graf     env->nip = bi->entry;
404cba2026aSAlexander Graf     mmubooke_create_initial_mapping(env);
4053b989d49SAlexander Graf }
4063b989d49SAlexander Graf 
407e6eaabebSScott Wood void ppce500_init(PPCE500Params *params)
4081db09b84Saurel32 {
40939186d8aSRichard Henderson     MemoryRegion *address_space_mem = get_system_memory();
4102646c133SAvi Kivity     MemoryRegion *ram = g_new(MemoryRegion, 1);
4111db09b84Saurel32     PCIBus *pci_bus;
412e2684c0bSAndreas Färber     CPUPPCState *env = NULL;
4131db09b84Saurel32     uint64_t elf_entry;
4141db09b84Saurel32     uint64_t elf_lowaddr;
415a8170e5eSAvi Kivity     hwaddr entry=0;
416a8170e5eSAvi Kivity     hwaddr loadaddr=UIMAGE_LOAD_BASE;
4171db09b84Saurel32     target_long kernel_size=0;
41875bb6589SLiu Yu     target_ulong dt_base = 0;
41975bb6589SLiu Yu     target_ulong initrd_base = 0;
4201db09b84Saurel32     target_long initrd_size=0;
4211db09b84Saurel32     int i=0;
4221db09b84Saurel32     unsigned int pci_irq_nrs[4] = {1, 2, 3, 4};
423a915249fSAlexander Graf     qemu_irq **irqs, *mpic;
424be13cc7aSAlexander Graf     DeviceState *dev;
425e2684c0bSAndreas Färber     CPUPPCState *firstenv = NULL;
426*3eddc1beSBharat Bhushan     MemoryRegion *ccsr_addr_space;
427dffb1dc2SBharat Bhushan     SysBusDevice *s;
428*3eddc1beSBharat Bhushan     PPCE500CCSRState *ccsr;
4291db09b84Saurel32 
430e61c36d5SAlexander Graf     /* Setup CPUs */
431e6eaabebSScott Wood     if (params->cpu_model == NULL) {
432e6eaabebSScott Wood         params->cpu_model = "e500v2_v30";
433ef250db6SAlexander Graf     }
434ef250db6SAlexander Graf 
435a915249fSAlexander Graf     irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *));
436a915249fSAlexander Graf     irqs[0] = g_malloc0(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
437e61c36d5SAlexander Graf     for (i = 0; i < smp_cpus; i++) {
438397b457dSAndreas Färber         PowerPCCPU *cpu;
439e61c36d5SAlexander Graf         qemu_irq *input;
440397b457dSAndreas Färber 
441e6eaabebSScott Wood         cpu = cpu_ppc_init(params->cpu_model);
442397b457dSAndreas Färber         if (cpu == NULL) {
4431db09b84Saurel32             fprintf(stderr, "Unable to initialize CPU!\n");
4441db09b84Saurel32             exit(1);
4451db09b84Saurel32         }
446397b457dSAndreas Färber         env = &cpu->env;
4471db09b84Saurel32 
448e61c36d5SAlexander Graf         if (!firstenv) {
449e61c36d5SAlexander Graf             firstenv = env;
450e61c36d5SAlexander Graf         }
451e61c36d5SAlexander Graf 
452a915249fSAlexander Graf         irqs[i] = irqs[0] + (i * OPENPIC_OUTPUT_NB);
453a915249fSAlexander Graf         input = (qemu_irq *)env->irq_inputs;
454a915249fSAlexander Graf         irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT];
455a915249fSAlexander Graf         irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT];
456e61c36d5SAlexander Graf         env->spr[SPR_BOOKE_PIR] = env->cpu_index = i;
457dffb1dc2SBharat Bhushan         env->mpic_cpu_base = MPC8544_CCSRBAR_BASE +
458dffb1dc2SBharat Bhushan                               MPC8544_MPIC_REGS_OFFSET + 0x20000;
459e61c36d5SAlexander Graf 
460ddd1055bSFabien Chouteau         ppc_booke_timers_init(env, 400000000, PPC_TIMER_E500);
4613b989d49SAlexander Graf 
4623b989d49SAlexander Graf         /* Register reset handler */
4635c145dacSAlexander Graf         if (!i) {
4645c145dacSAlexander Graf             /* Primary CPU */
4655c145dacSAlexander Graf             struct boot_info *boot_info;
466e61c36d5SAlexander Graf             boot_info = g_malloc0(sizeof(struct boot_info));
467b3305981SScott Wood             qemu_register_reset(ppce500_cpu_reset, cpu);
468e61c36d5SAlexander Graf             env->load_info = boot_info;
4695c145dacSAlexander Graf         } else {
4705c145dacSAlexander Graf             /* Secondary CPUs */
471b3305981SScott Wood             qemu_register_reset(ppce500_cpu_reset_sec, cpu);
4725c145dacSAlexander Graf         }
473e61c36d5SAlexander Graf     }
474e61c36d5SAlexander Graf 
475e61c36d5SAlexander Graf     env = firstenv;
4763b989d49SAlexander Graf 
4771db09b84Saurel32     /* Fixup Memory size on a alignment boundary */
4781db09b84Saurel32     ram_size &= ~(RAM_SIZES_ALIGN - 1);
4791db09b84Saurel32 
4801db09b84Saurel32     /* Register Memory */
481c5705a77SAvi Kivity     memory_region_init_ram(ram, "mpc8544ds.ram", ram_size);
482c5705a77SAvi Kivity     vmstate_register_ram_global(ram);
4832646c133SAvi Kivity     memory_region_add_subregion(address_space_mem, 0, ram);
4841db09b84Saurel32 
485*3eddc1beSBharat Bhushan     dev = qdev_create(NULL, "e500-ccsr");
486*3eddc1beSBharat Bhushan     object_property_add_child(qdev_get_machine(), "e500-ccsr",
487*3eddc1beSBharat Bhushan                               OBJECT(dev), NULL);
488*3eddc1beSBharat Bhushan     qdev_init_nofail(dev);
489*3eddc1beSBharat Bhushan     ccsr = CCSR(dev);
490*3eddc1beSBharat Bhushan     ccsr_addr_space = &ccsr->ccsr_space;
491*3eddc1beSBharat Bhushan     memory_region_add_subregion(address_space_mem, MPC8544_CCSRBAR_BASE,
492*3eddc1beSBharat Bhushan                                 ccsr_addr_space);
493dffb1dc2SBharat Bhushan 
4941db09b84Saurel32     /* MPIC */
495*3eddc1beSBharat Bhushan     mpic = mpic_init(ccsr_addr_space, MPC8544_MPIC_REGS_OFFSET,
496df2921d3SAvi Kivity                      smp_cpus, irqs, NULL);
497a915249fSAlexander Graf 
498a915249fSAlexander Graf     if (!mpic) {
499a915249fSAlexander Graf         cpu_abort(env, "MPIC failed to initialize\n");
500a915249fSAlexander Graf     }
5011db09b84Saurel32 
5021db09b84Saurel32     /* Serial */
5032d48377aSBlue Swirl     if (serial_hds[0]) {
504*3eddc1beSBharat Bhushan         serial_mm_init(ccsr_addr_space, MPC8544_SERIAL0_REGS_OFFSET,
5051db09b84Saurel32                        0, mpic[12+26], 399193,
5062ff0c7c3SRichard Henderson                        serial_hds[0], DEVICE_BIG_ENDIAN);
5072d48377aSBlue Swirl     }
5081db09b84Saurel32 
5092d48377aSBlue Swirl     if (serial_hds[1]) {
510*3eddc1beSBharat Bhushan         serial_mm_init(ccsr_addr_space, MPC8544_SERIAL1_REGS_OFFSET,
5111db09b84Saurel32                        0, mpic[12+26], 399193,
51259de4f98SBharat Bhushan                        serial_hds[1], DEVICE_BIG_ENDIAN);
5132d48377aSBlue Swirl     }
5141db09b84Saurel32 
515b0fb8423SAlexander Graf     /* General Utility device */
516dffb1dc2SBharat Bhushan     dev = qdev_create(NULL, "mpc8544-guts");
517dffb1dc2SBharat Bhushan     qdev_init_nofail(dev);
518dffb1dc2SBharat Bhushan     s = SYS_BUS_DEVICE(dev);
519*3eddc1beSBharat Bhushan     memory_region_add_subregion(ccsr_addr_space, MPC8544_UTIL_OFFSET,
520dffb1dc2SBharat Bhushan                                 sysbus_mmio_get_region(s, 0));
521b0fb8423SAlexander Graf 
5221db09b84Saurel32     /* PCI */
523dffb1dc2SBharat Bhushan     dev = qdev_create(NULL, "e500-pcihost");
524dffb1dc2SBharat Bhushan     qdev_init_nofail(dev);
525dffb1dc2SBharat Bhushan     s = SYS_BUS_DEVICE(dev);
526dffb1dc2SBharat Bhushan     sysbus_connect_irq(s, 0, mpic[pci_irq_nrs[0]]);
527dffb1dc2SBharat Bhushan     sysbus_connect_irq(s, 1, mpic[pci_irq_nrs[1]]);
528dffb1dc2SBharat Bhushan     sysbus_connect_irq(s, 2, mpic[pci_irq_nrs[2]]);
529dffb1dc2SBharat Bhushan     sysbus_connect_irq(s, 3, mpic[pci_irq_nrs[3]]);
530*3eddc1beSBharat Bhushan     memory_region_add_subregion(ccsr_addr_space, MPC8544_PCI_REGS_OFFSET,
531dffb1dc2SBharat Bhushan                                 sysbus_mmio_get_region(s, 0));
532dffb1dc2SBharat Bhushan 
533d461e3b9SAlexander Graf     pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
5341db09b84Saurel32     if (!pci_bus)
5351db09b84Saurel32         printf("couldn't create PCI controller!\n");
5361db09b84Saurel32 
537a1bc20dfSAlexander Graf     sysbus_mmio_map(sysbus_from_qdev(dev), 1, MPC8544_PCI_IO);
5381db09b84Saurel32 
5391db09b84Saurel32     if (pci_bus) {
5401db09b84Saurel32         /* Register network interfaces. */
5411db09b84Saurel32         for (i = 0; i < nb_nics; i++) {
54207caea31SMarkus Armbruster             pci_nic_init_nofail(&nd_table[i], "virtio", NULL);
5431db09b84Saurel32         }
5441db09b84Saurel32     }
5451db09b84Saurel32 
5465c145dacSAlexander Graf     /* Register spinning region */
5475c145dacSAlexander Graf     sysbus_create_simple("e500-spin", MPC8544_SPIN_BASE, NULL);
5485c145dacSAlexander Graf 
5491db09b84Saurel32     /* Load kernel. */
550e6eaabebSScott Wood     if (params->kernel_filename) {
551e6eaabebSScott Wood         kernel_size = load_uimage(params->kernel_filename, &entry,
552e6eaabebSScott Wood                                   &loadaddr, NULL);
5531db09b84Saurel32         if (kernel_size < 0) {
554e6eaabebSScott Wood             kernel_size = load_elf(params->kernel_filename, NULL, NULL,
555e6eaabebSScott Wood                                    &elf_entry, &elf_lowaddr, NULL, 1,
556e6eaabebSScott Wood                                    ELF_MACHINE, 0);
5571db09b84Saurel32             entry = elf_entry;
5581db09b84Saurel32             loadaddr = elf_lowaddr;
5591db09b84Saurel32         }
5601db09b84Saurel32         /* XXX try again as binary */
5611db09b84Saurel32         if (kernel_size < 0) {
5621db09b84Saurel32             fprintf(stderr, "qemu: could not load kernel '%s'\n",
563e6eaabebSScott Wood                     params->kernel_filename);
5641db09b84Saurel32             exit(1);
5651db09b84Saurel32         }
5661db09b84Saurel32     }
5671db09b84Saurel32 
5681db09b84Saurel32     /* Load initrd. */
569e6eaabebSScott Wood     if (params->initrd_filename) {
5707e7ec2d2SScott Wood         initrd_base = (loadaddr + kernel_size + INITRD_LOAD_PAD) &
5717e7ec2d2SScott Wood             ~INITRD_PAD_MASK;
572e6eaabebSScott Wood         initrd_size = load_image_targphys(params->initrd_filename, initrd_base,
573d7585251Spbrook                                           ram_size - initrd_base);
5741db09b84Saurel32 
5751db09b84Saurel32         if (initrd_size < 0) {
5761db09b84Saurel32             fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
577e6eaabebSScott Wood                     params->initrd_filename);
5781db09b84Saurel32             exit(1);
5791db09b84Saurel32         }
5801db09b84Saurel32     }
5811db09b84Saurel32 
5821db09b84Saurel32     /* If we're loading a kernel directly, we must load the device tree too. */
583e6eaabebSScott Wood     if (params->kernel_filename) {
5845c145dacSAlexander Graf         struct boot_info *boot_info;
585cba2026aSAlexander Graf         int dt_size;
5865c145dacSAlexander Graf 
587cba2026aSAlexander Graf         dt_base = (loadaddr + kernel_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
588e6eaabebSScott Wood         dt_size = ppce500_load_device_tree(env, params, dt_base, initrd_base,
589e6eaabebSScott Wood                                            initrd_size);
590cba2026aSAlexander Graf         if (dt_size < 0) {
5911db09b84Saurel32             fprintf(stderr, "couldn't load device tree\n");
5921db09b84Saurel32             exit(1);
5931db09b84Saurel32         }
5941db09b84Saurel32 
595e61c36d5SAlexander Graf         boot_info = env->load_info;
5963b989d49SAlexander Graf         boot_info->entry = entry;
5973b989d49SAlexander Graf         boot_info->dt_base = dt_base;
598cba2026aSAlexander Graf         boot_info->dt_size = dt_size;
5991db09b84Saurel32     }
6001db09b84Saurel32 
6013b989d49SAlexander Graf     if (kvm_enabled()) {
6021db09b84Saurel32         kvmppc_init();
6033b989d49SAlexander Graf     }
6041db09b84Saurel32 }
605*3eddc1beSBharat Bhushan 
606*3eddc1beSBharat Bhushan static int e500_ccsr_initfn(SysBusDevice *dev)
607*3eddc1beSBharat Bhushan {
608*3eddc1beSBharat Bhushan     PPCE500CCSRState *ccsr;
609*3eddc1beSBharat Bhushan 
610*3eddc1beSBharat Bhushan     ccsr = CCSR(dev);
611*3eddc1beSBharat Bhushan     memory_region_init(&ccsr->ccsr_space, "e500-ccsr",
612*3eddc1beSBharat Bhushan                        MPC8544_CCSRBAR_SIZE);
613*3eddc1beSBharat Bhushan     return 0;
614*3eddc1beSBharat Bhushan }
615*3eddc1beSBharat Bhushan 
616*3eddc1beSBharat Bhushan static void e500_ccsr_class_init(ObjectClass *klass, void *data)
617*3eddc1beSBharat Bhushan {
618*3eddc1beSBharat Bhushan     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
619*3eddc1beSBharat Bhushan     k->init = e500_ccsr_initfn;
620*3eddc1beSBharat Bhushan }
621*3eddc1beSBharat Bhushan 
622*3eddc1beSBharat Bhushan static const TypeInfo e500_ccsr_info = {
623*3eddc1beSBharat Bhushan     .name          = TYPE_CCSR,
624*3eddc1beSBharat Bhushan     .parent        = TYPE_SYS_BUS_DEVICE,
625*3eddc1beSBharat Bhushan     .instance_size = sizeof(PPCE500CCSRState),
626*3eddc1beSBharat Bhushan     .class_init    = e500_ccsr_class_init,
627*3eddc1beSBharat Bhushan };
628*3eddc1beSBharat Bhushan 
629*3eddc1beSBharat Bhushan static void e500_register_types(void)
630*3eddc1beSBharat Bhushan {
631*3eddc1beSBharat Bhushan     type_register_static(&e500_ccsr_info);
632*3eddc1beSBharat Bhushan }
633*3eddc1beSBharat Bhushan 
634*3eddc1beSBharat Bhushan type_init(e500_register_types)
635