]> git.proxmox.com Git - mirror_qemu.git/blame - hw/ppce500_mpc8544ds.c
PPC: e500: Use new MPIC dt format
[mirror_qemu.git] / hw / ppce500_mpc8544ds.c
CommitLineData
1db09b84 1/*
5cbdb3a3 2 * QEMU PowerPC MPC8544DS board emulation
1db09b84
AJ
3 *
4 * Copyright (C) 2009 Freescale Semiconductor, Inc. All rights reserved.
5 *
6 * Author: Yu Liu, <yu.liu@freescale.com>
7 *
8 * This file is derived from hw/ppc440_bamboo.c,
9 * the copyright for that material belongs to the original owners.
10 *
11 * This is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 */
16
1db09b84
AJ
17#include "config.h"
18#include "qemu-common.h"
19#include "net.h"
20#include "hw.h"
21#include "pc.h"
22#include "pci.h"
1db09b84
AJ
23#include "boards.h"
24#include "sysemu.h"
25#include "kvm.h"
26#include "kvm_ppc.h"
27#include "device_tree.h"
28#include "openpic.h"
3b989d49 29#include "ppc.h"
ca20cf32
BS
30#include "loader.h"
31#include "elf.h"
be13cc7a 32#include "sysbus.h"
39186d8a 33#include "exec-memory.h"
cba2026a 34#include "host-utils.h"
1db09b84
AJ
35
36#define BINARY_DEVICE_TREE_FILE "mpc8544ds.dtb"
37#define UIMAGE_LOAD_BASE 0
75bb6589
LY
38#define DTC_LOAD_PAD 0x500000
39#define DTC_PAD_MASK 0xFFFFF
40#define INITRD_LOAD_PAD 0x2000000
41#define INITRD_PAD_MASK 0xFFFFFF
1db09b84
AJ
42
43#define RAM_SIZES_ALIGN (64UL << 20)
44
45#define MPC8544_CCSRBAR_BASE 0xE0000000
5da96624
AG
46#define MPC8544_CCSRBAR_REGSIZE 0x00001000
47#define MPC8544_CCSRBAR_SIZE 0x00100000
1db09b84
AJ
48#define MPC8544_MPIC_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x40000)
49#define MPC8544_SERIAL0_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x4500)
50#define MPC8544_SERIAL1_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x4600)
51#define MPC8544_PCI_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x8000)
52#define MPC8544_PCI_REGS_SIZE 0x1000
53#define MPC8544_PCI_IO 0xE1000000
54#define MPC8544_PCI_IOLEN 0x10000
b0fb8423 55#define MPC8544_UTIL_BASE (MPC8544_CCSRBAR_BASE + 0xe0000)
5c145dac 56#define MPC8544_SPIN_BASE 0xEF000000
1db09b84 57
3b989d49
AG
58struct boot_info
59{
60 uint32_t dt_base;
cba2026a 61 uint32_t dt_size;
3b989d49
AG
62 uint32_t entry;
63};
64
0dbc0798
AG
65static void pci_map_create(void *fdt, uint32_t *pci_map, uint32_t mpic)
66{
67 int i;
68 const uint32_t tmp[] = {
69 /* IDSEL 0x11 J17 Slot 1 */
518c7fb4
AG
70 0x8800, 0x0, 0x0, 0x1, mpic, 0x2, 0x1, 0x0, 0x0,
71 0x8800, 0x0, 0x0, 0x2, mpic, 0x3, 0x1, 0x0, 0x0,
72 0x8800, 0x0, 0x0, 0x3, mpic, 0x4, 0x1, 0x0, 0x0,
73 0x8800, 0x0, 0x0, 0x4, mpic, 0x1, 0x1, 0x0, 0x0,
0dbc0798
AG
74
75 /* IDSEL 0x12 J16 Slot 2 */
518c7fb4
AG
76 0x9000, 0x0, 0x0, 0x1, mpic, 0x3, 0x1, 0x0, 0x0,
77 0x9000, 0x0, 0x0, 0x2, mpic, 0x4, 0x1, 0x0, 0x0,
78 0x9000, 0x0, 0x0, 0x3, mpic, 0x2, 0x1, 0x0, 0x0,
79 0x9000, 0x0, 0x0, 0x4, mpic, 0x1, 0x1, 0x0, 0x0,
0dbc0798 80 };
518c7fb4 81 for (i = 0; i < ARRAY_SIZE(tmp); i++) {
0dbc0798
AG
82 pci_map[i] = cpu_to_be32(tmp[i]);
83 }
84}
85
e2684c0b 86static int mpc8544_load_device_tree(CPUPPCState *env,
5de6b46d 87 target_phys_addr_t addr,
7f47b41f 88 target_phys_addr_t ramsize,
5de6b46d
AG
89 target_phys_addr_t initrd_base,
90 target_phys_addr_t initrd_size,
91 const char *kernel_cmdline)
1db09b84 92{
dbf916d8 93 int ret = -1;
3b989d49 94 uint32_t mem_reg_property[] = {0, cpu_to_be32(ramsize)};
7ec632b4 95 int fdt_size;
dbf916d8 96 void *fdt;
5de6b46d 97 uint8_t hypercall[16];
911d6e7a
AG
98 uint32_t clock_freq = 400000000;
99 uint32_t tb_freq = 400000000;
621d05e3 100 int i;
51b852b7
AG
101 char compatible[] = "MPC8544DS\0MPC85xxDS";
102 char model[] = "MPC8544DS";
5da96624 103 char soc[128];
0cfc6e8d
AG
104 char ser0[128];
105 char ser1[128];
19ac9dea
AG
106 char mpic[128];
107 uint32_t mpic_ph;
f5038483 108 char gutil[128];
0dbc0798 109 char pci[128];
518c7fb4 110 uint32_t pci_map[9 * 8];
0dbc0798
AG
111 uint32_t pci_ranges[12] = { 0x2000000, 0x0, 0xc0000000, 0xc0000000, 0x0,
112 0x20000000, 0x1000000, 0x0, 0x0, 0xe1000000,
113 0x0, 0x10000 };
25b42708
AG
114 QemuOpts *machine_opts;
115 const char *dumpdtb = NULL;
d1b93565
AG
116 const char *dtb_file = NULL;
117
118 machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0);
119 if (machine_opts) {
120 dumpdtb = qemu_opt_get(machine_opts, "dumpdtb");
121 dtb_file = qemu_opt_get(machine_opts, "dtb");
122 }
123
124 if (dtb_file) {
125 char *filename;
126 filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_file);
127 if (!filename) {
128 goto out;
129 }
130
131 fdt = load_device_tree(filename, &fdt_size);
132 if (!fdt) {
133 goto out;
134 }
135 goto done;
136 }
1db09b84 137
2636fcb6 138 fdt = create_device_tree(&fdt_size);
5cea8590
PB
139 if (fdt == NULL) {
140 goto out;
141 }
1db09b84
AJ
142
143 /* Manipulate device tree in memory. */
51b852b7
AG
144 qemu_devtree_setprop_string(fdt, "/", "model", model);
145 qemu_devtree_setprop(fdt, "/", "compatible", compatible,
146 sizeof(compatible));
147 qemu_devtree_setprop_cell(fdt, "/", "#address-cells", 1);
148 qemu_devtree_setprop_cell(fdt, "/", "#size-cells", 1);
149
dd0bcfca
AG
150 qemu_devtree_add_subnode(fdt, "/memory");
151 qemu_devtree_setprop_string(fdt, "/memory", "device_type", "memory");
152 qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property,
153 sizeof(mem_reg_property));
1db09b84 154
f5231aaf 155 qemu_devtree_add_subnode(fdt, "/chosen");
3b989d49
AG
156 if (initrd_size) {
157 ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start",
158 initrd_base);
159 if (ret < 0) {
160 fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
161 }
1db09b84 162
3b989d49
AG
163 ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end",
164 (initrd_base + initrd_size));
165 if (ret < 0) {
166 fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
167 }
168 }
1db09b84
AJ
169
170 ret = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs",
171 kernel_cmdline);
172 if (ret < 0)
173 fprintf(stderr, "couldn't set /chosen/bootargs\n");
174
175 if (kvm_enabled()) {
911d6e7a
AG
176 /* Read out host's frequencies */
177 clock_freq = kvmppc_get_clockfreq();
178 tb_freq = kvmppc_get_tbfreq();
5de6b46d
AG
179
180 /* indicate KVM hypercall interface */
d50f71a5 181 qemu_devtree_add_subnode(fdt, "/hypervisor");
5de6b46d
AG
182 qemu_devtree_setprop_string(fdt, "/hypervisor", "compatible",
183 "linux,kvm");
184 kvmppc_get_hypercall(env, hypercall, sizeof(hypercall));
185 qemu_devtree_setprop(fdt, "/hypervisor", "hcall-instructions",
186 hypercall, sizeof(hypercall));
1db09b84 187 }
3b989d49 188
625e665b
AG
189 /* Create CPU nodes */
190 qemu_devtree_add_subnode(fdt, "/cpus");
191 qemu_devtree_setprop_cell(fdt, "/cpus", "#address-cells", 1);
192 qemu_devtree_setprop_cell(fdt, "/cpus", "#size-cells", 0);
193
1e3debf0
AG
194 /* We need to generate the cpu nodes in reverse order, so Linux can pick
195 the first node as boot node and be happy */
196 for (i = smp_cpus - 1; i >= 0; i--) {
621d05e3 197 char cpu_name[128];
1d2e5c52 198 uint64_t cpu_release_addr = MPC8544_SPIN_BASE + (i * 0x20);
10f25a46 199
1e3debf0
AG
200 for (env = first_cpu; env != NULL; env = env->next_cpu) {
201 if (env->cpu_index == i) {
202 break;
203 }
204 }
205
206 if (!env) {
207 continue;
208 }
209
210 snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x", env->cpu_index);
211 qemu_devtree_add_subnode(fdt, cpu_name);
621d05e3
AG
212 qemu_devtree_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq);
213 qemu_devtree_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq);
1e3debf0
AG
214 qemu_devtree_setprop_string(fdt, cpu_name, "device_type", "cpu");
215 qemu_devtree_setprop_cell(fdt, cpu_name, "reg", env->cpu_index);
216 qemu_devtree_setprop_cell(fdt, cpu_name, "d-cache-line-size",
217 env->dcache_line_size);
218 qemu_devtree_setprop_cell(fdt, cpu_name, "i-cache-line-size",
219 env->icache_line_size);
220 qemu_devtree_setprop_cell(fdt, cpu_name, "d-cache-size", 0x8000);
221 qemu_devtree_setprop_cell(fdt, cpu_name, "i-cache-size", 0x8000);
222 qemu_devtree_setprop_cell(fdt, cpu_name, "bus-frequency", 0);
223 if (env->cpu_index) {
224 qemu_devtree_setprop_string(fdt, cpu_name, "status", "disabled");
225 qemu_devtree_setprop_string(fdt, cpu_name, "enable-method", "spin-table");
1d2e5c52
AG
226 qemu_devtree_setprop_u64(fdt, cpu_name, "cpu-release-addr",
227 cpu_release_addr);
1e3debf0
AG
228 } else {
229 qemu_devtree_setprop_string(fdt, cpu_name, "status", "okay");
230 }
1db09b84
AJ
231 }
232
0cfc6e8d 233 qemu_devtree_add_subnode(fdt, "/aliases");
5da96624
AG
234 /* XXX These should go into their respective devices' code */
235 snprintf(soc, sizeof(soc), "/soc8544@%x", MPC8544_CCSRBAR_BASE);
236 qemu_devtree_add_subnode(fdt, soc);
237 qemu_devtree_setprop_string(fdt, soc, "device_type", "soc");
238 qemu_devtree_setprop_string(fdt, soc, "compatible", "simple-bus");
239 qemu_devtree_setprop_cell(fdt, soc, "#address-cells", 1);
240 qemu_devtree_setprop_cell(fdt, soc, "#size-cells", 1);
241 qemu_devtree_setprop_cells(fdt, soc, "ranges", 0x0, MPC8544_CCSRBAR_BASE,
242 MPC8544_CCSRBAR_SIZE);
243 qemu_devtree_setprop_cells(fdt, soc, "reg", MPC8544_CCSRBAR_BASE,
244 MPC8544_CCSRBAR_REGSIZE);
245 /* XXX should contain a reasonable value */
246 qemu_devtree_setprop_cell(fdt, soc, "bus-frequency", 0);
247
19ac9dea
AG
248 snprintf(mpic, sizeof(mpic), "%s/pic@%x", soc,
249 MPC8544_MPIC_REGS_BASE - MPC8544_CCSRBAR_BASE);
250 qemu_devtree_add_subnode(fdt, mpic);
251 qemu_devtree_setprop_string(fdt, mpic, "device_type", "open-pic");
518c7fb4 252 qemu_devtree_setprop_string(fdt, mpic, "compatible", "fsl,mpic");
19ac9dea
AG
253 qemu_devtree_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_BASE -
254 MPC8544_CCSRBAR_BASE, 0x40000);
255 qemu_devtree_setprop_cell(fdt, mpic, "#address-cells", 0);
518c7fb4 256 qemu_devtree_setprop_cell(fdt, mpic, "#interrupt-cells", 4);
19ac9dea
AG
257 mpic_ph = qemu_devtree_alloc_phandle(fdt);
258 qemu_devtree_setprop_cell(fdt, mpic, "phandle", mpic_ph);
259 qemu_devtree_setprop_cell(fdt, mpic, "linux,phandle", mpic_ph);
260 qemu_devtree_setprop(fdt, mpic, "interrupt-controller", NULL, 0);
518c7fb4
AG
261 qemu_devtree_setprop(fdt, mpic, "big-endian", NULL, 0);
262 qemu_devtree_setprop(fdt, mpic, "single-cpu-affinity", NULL, 0);
263 qemu_devtree_setprop_cell(fdt, mpic, "last-interrupt-source", 255);
19ac9dea 264
0cfc6e8d
AG
265 /*
266 * We have to generate ser1 first, because Linux takes the first
267 * device it finds in the dt as serial output device. And we generate
268 * devices in reverse order to the dt.
269 */
270 snprintf(ser1, sizeof(ser1), "%s/serial@%x", soc,
271 MPC8544_SERIAL1_REGS_BASE - MPC8544_CCSRBAR_BASE);
272 qemu_devtree_add_subnode(fdt, ser1);
273 qemu_devtree_setprop_string(fdt, ser1, "device_type", "serial");
274 qemu_devtree_setprop_string(fdt, ser1, "compatible", "ns16550");
275 qemu_devtree_setprop_cells(fdt, ser1, "reg", MPC8544_SERIAL1_REGS_BASE -
276 MPC8544_CCSRBAR_BASE, 0x100);
277 qemu_devtree_setprop_cell(fdt, ser1, "cell-index", 1);
278 qemu_devtree_setprop_cell(fdt, ser1, "clock-frequency", 0);
518c7fb4 279 qemu_devtree_setprop_cells(fdt, ser1, "interrupts", 42, 2, 0, 0);
0cfc6e8d
AG
280 qemu_devtree_setprop_phandle(fdt, ser1, "interrupt-parent", mpic);
281 qemu_devtree_setprop_string(fdt, "/aliases", "serial1", ser1);
282
283 snprintf(ser0, sizeof(ser0), "%s/serial@%x", soc,
284 MPC8544_SERIAL0_REGS_BASE - MPC8544_CCSRBAR_BASE);
285 qemu_devtree_add_subnode(fdt, ser0);
286 qemu_devtree_setprop_string(fdt, ser0, "device_type", "serial");
287 qemu_devtree_setprop_string(fdt, ser0, "compatible", "ns16550");
288 qemu_devtree_setprop_cells(fdt, ser0, "reg", MPC8544_SERIAL0_REGS_BASE -
289 MPC8544_CCSRBAR_BASE, 0x100);
290 qemu_devtree_setprop_cell(fdt, ser0, "cell-index", 0);
291 qemu_devtree_setprop_cell(fdt, ser0, "clock-frequency", 0);
518c7fb4 292 qemu_devtree_setprop_cells(fdt, ser0, "interrupts", 42, 2, 0, 0);
0cfc6e8d
AG
293 qemu_devtree_setprop_phandle(fdt, ser0, "interrupt-parent", mpic);
294 qemu_devtree_setprop_string(fdt, "/aliases", "serial0", ser0);
295 qemu_devtree_setprop_string(fdt, "/chosen", "linux,stdout-path", ser0);
296
f5038483
AG
297 snprintf(gutil, sizeof(gutil), "%s/global-utilities@%x", soc,
298 MPC8544_UTIL_BASE - MPC8544_CCSRBAR_BASE);
299 qemu_devtree_add_subnode(fdt, gutil);
300 qemu_devtree_setprop_string(fdt, gutil, "compatible", "fsl,mpc8544-guts");
301 qemu_devtree_setprop_cells(fdt, gutil, "reg", MPC8544_UTIL_BASE -
302 MPC8544_CCSRBAR_BASE, 0x1000);
303 qemu_devtree_setprop(fdt, gutil, "fsl,has-rstcr", NULL, 0);
304
0dbc0798
AG
305 snprintf(pci, sizeof(pci), "/pci@%x", MPC8544_PCI_REGS_BASE);
306 qemu_devtree_add_subnode(fdt, pci);
307 qemu_devtree_setprop_cell(fdt, pci, "cell-index", 0);
308 qemu_devtree_setprop_string(fdt, pci, "compatible", "fsl,mpc8540-pci");
309 qemu_devtree_setprop_string(fdt, pci, "device_type", "pci");
310 qemu_devtree_setprop_cells(fdt, pci, "interrupt-map-mask", 0xf800, 0x0,
311 0x0, 0x7);
312 pci_map_create(fdt, pci_map, qemu_devtree_get_phandle(fdt, mpic));
313 qemu_devtree_setprop(fdt, pci, "interrupt-map", pci_map, sizeof(pci_map));
314 qemu_devtree_setprop_phandle(fdt, pci, "interrupt-parent", mpic);
518c7fb4 315 qemu_devtree_setprop_cells(fdt, pci, "interrupts", 24, 2, 0, 0);
0dbc0798
AG
316 qemu_devtree_setprop_cells(fdt, pci, "bus-range", 0, 255);
317 for (i = 0; i < 12; i++) {
318 pci_ranges[i] = cpu_to_be32(pci_ranges[i]);
319 }
320 qemu_devtree_setprop(fdt, pci, "ranges", pci_ranges, sizeof(pci_ranges));
321 qemu_devtree_setprop_cells(fdt, pci, "reg", MPC8544_PCI_REGS_BASE,
322 0x1000);
323 qemu_devtree_setprop_cell(fdt, pci, "clock-frequency", 66666666);
324 qemu_devtree_setprop_cell(fdt, pci, "#interrupt-cells", 1);
325 qemu_devtree_setprop_cell(fdt, pci, "#size-cells", 2);
326 qemu_devtree_setprop_cell(fdt, pci, "#address-cells", 3);
327 qemu_devtree_setprop_string(fdt, "/aliases", "pci0", pci);
328
d1b93565 329done:
25b42708
AG
330 if (dumpdtb) {
331 /* Dump the dtb to a file and quit */
332 FILE *f = fopen(dumpdtb, "wb");
333 size_t len;
334 len = fwrite(fdt, fdt_size, 1, f);
335 fclose(f);
336 if (len != fdt_size) {
337 exit(1);
338 }
339 exit(0);
340 }
341
04088adb 342 ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
cba2026a
AG
343 if (ret < 0) {
344 goto out;
345 }
7267c094 346 g_free(fdt);
cba2026a 347 ret = fdt_size;
7ec632b4 348
1db09b84 349out:
1db09b84 350
04088adb 351 return ret;
1db09b84
AJ
352}
353
cba2026a 354/* Create -kernel TLB entries for BookE. */
d1e256fe
AG
355static inline target_phys_addr_t booke206_page_size_to_tlb(uint64_t size)
356{
cba2026a 357 return 63 - clz64(size >> 10);
d1e256fe
AG
358}
359
cba2026a 360static void mmubooke_create_initial_mapping(CPUPPCState *env)
3b989d49 361{
cba2026a 362 struct boot_info *bi = env->load_info;
d1e256fe 363 ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0);
cba2026a
AG
364 target_phys_addr_t size, dt_end;
365 int ps;
366
367 /* Our initial TLB entry needs to cover everything from 0 to
368 the device tree top */
369 dt_end = bi->dt_base + bi->dt_size;
370 ps = booke206_page_size_to_tlb(dt_end) + 1;
371 size = (ps << MAS1_TSIZE_SHIFT);
d1e256fe 372 tlb->mas1 = MAS1_VALID | size;
cba2026a
AG
373 tlb->mas2 = 0;
374 tlb->mas7_3 = 0;
d1e256fe 375 tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
93dd5e85
SW
376
377 env->tlb_dirty = true;
3b989d49
AG
378}
379
5c145dac
AG
380static void mpc8544ds_cpu_reset_sec(void *opaque)
381{
38f92da6
AF
382 PowerPCCPU *cpu = opaque;
383 CPUPPCState *env = &cpu->env;
5c145dac 384
38f92da6 385 cpu_reset(CPU(cpu));
5c145dac
AG
386
387 /* Secondary CPU starts in halted state for now. Needs to change when
388 implementing non-kernel boot. */
389 env->halted = 1;
390 env->exception_index = EXCP_HLT;
3b989d49
AG
391}
392
393static void mpc8544ds_cpu_reset(void *opaque)
394{
38f92da6
AF
395 PowerPCCPU *cpu = opaque;
396 CPUPPCState *env = &cpu->env;
3b989d49
AG
397 struct boot_info *bi = env->load_info;
398
38f92da6 399 cpu_reset(CPU(cpu));
3b989d49
AG
400
401 /* Set initial guest state. */
5c145dac 402 env->halted = 0;
3b989d49
AG
403 env->gpr[1] = (16<<20) - 8;
404 env->gpr[3] = bi->dt_base;
405 env->nip = bi->entry;
cba2026a 406 mmubooke_create_initial_mapping(env);
3b989d49
AG
407}
408
c227f099 409static void mpc8544ds_init(ram_addr_t ram_size,
1db09b84
AJ
410 const char *boot_device,
411 const char *kernel_filename,
412 const char *kernel_cmdline,
413 const char *initrd_filename,
414 const char *cpu_model)
415{
39186d8a 416 MemoryRegion *address_space_mem = get_system_memory();
2646c133 417 MemoryRegion *ram = g_new(MemoryRegion, 1);
1db09b84 418 PCIBus *pci_bus;
e2684c0b 419 CPUPPCState *env = NULL;
1db09b84
AJ
420 uint64_t elf_entry;
421 uint64_t elf_lowaddr;
c227f099
AL
422 target_phys_addr_t entry=0;
423 target_phys_addr_t loadaddr=UIMAGE_LOAD_BASE;
1db09b84 424 target_long kernel_size=0;
75bb6589
LY
425 target_ulong dt_base = 0;
426 target_ulong initrd_base = 0;
1db09b84 427 target_long initrd_size=0;
1db09b84
AJ
428 int i=0;
429 unsigned int pci_irq_nrs[4] = {1, 2, 3, 4};
a915249f 430 qemu_irq **irqs, *mpic;
be13cc7a 431 DeviceState *dev;
e2684c0b 432 CPUPPCState *firstenv = NULL;
1db09b84 433
e61c36d5 434 /* Setup CPUs */
ef250db6
AG
435 if (cpu_model == NULL) {
436 cpu_model = "e500v2_v30";
437 }
438
a915249f
AG
439 irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *));
440 irqs[0] = g_malloc0(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
e61c36d5 441 for (i = 0; i < smp_cpus; i++) {
397b457d 442 PowerPCCPU *cpu;
e61c36d5 443 qemu_irq *input;
397b457d
AF
444
445 cpu = cpu_ppc_init(cpu_model);
446 if (cpu == NULL) {
e61c36d5
AG
447 fprintf(stderr, "Unable to initialize CPU!\n");
448 exit(1);
449 }
397b457d 450 env = &cpu->env;
1db09b84 451
e61c36d5
AG
452 if (!firstenv) {
453 firstenv = env;
454 }
1db09b84 455
a915249f
AG
456 irqs[i] = irqs[0] + (i * OPENPIC_OUTPUT_NB);
457 input = (qemu_irq *)env->irq_inputs;
458 irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT];
459 irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT];
e61c36d5 460 env->spr[SPR_BOOKE_PIR] = env->cpu_index = i;
3b989d49 461
ddd1055b 462 ppc_booke_timers_init(env, 400000000, PPC_TIMER_E500);
e61c36d5
AG
463
464 /* Register reset handler */
5c145dac
AG
465 if (!i) {
466 /* Primary CPU */
467 struct boot_info *boot_info;
468 boot_info = g_malloc0(sizeof(struct boot_info));
38f92da6 469 qemu_register_reset(mpc8544ds_cpu_reset, cpu);
5c145dac
AG
470 env->load_info = boot_info;
471 } else {
472 /* Secondary CPUs */
38f92da6 473 qemu_register_reset(mpc8544ds_cpu_reset_sec, cpu);
5c145dac 474 }
e61c36d5 475 }
3b989d49 476
e61c36d5 477 env = firstenv;
3b989d49 478
1db09b84
AJ
479 /* Fixup Memory size on a alignment boundary */
480 ram_size &= ~(RAM_SIZES_ALIGN - 1);
481
482 /* Register Memory */
c5705a77
AK
483 memory_region_init_ram(ram, "mpc8544ds.ram", ram_size);
484 vmstate_register_ram_global(ram);
2646c133 485 memory_region_add_subregion(address_space_mem, 0, ram);
1db09b84
AJ
486
487 /* MPIC */
df2921d3
AK
488 mpic = mpic_init(address_space_mem, MPC8544_MPIC_REGS_BASE,
489 smp_cpus, irqs, NULL);
a915249f
AG
490
491 if (!mpic) {
492 cpu_abort(env, "MPIC failed to initialize\n");
493 }
1db09b84
AJ
494
495 /* Serial */
2d48377a 496 if (serial_hds[0]) {
39186d8a 497 serial_mm_init(address_space_mem, MPC8544_SERIAL0_REGS_BASE,
49a2942d 498 0, mpic[12+26], 399193,
2ff0c7c3 499 serial_hds[0], DEVICE_BIG_ENDIAN);
2d48377a 500 }
1db09b84 501
2d48377a 502 if (serial_hds[1]) {
39186d8a 503 serial_mm_init(address_space_mem, MPC8544_SERIAL1_REGS_BASE,
49a2942d 504 0, mpic[12+26], 399193,
2ff0c7c3 505 serial_hds[0], DEVICE_BIG_ENDIAN);
2d48377a 506 }
1db09b84 507
b0fb8423
AG
508 /* General Utility device */
509 sysbus_create_simple("mpc8544-guts", MPC8544_UTIL_BASE, NULL);
510
1db09b84 511 /* PCI */
be13cc7a
AG
512 dev = sysbus_create_varargs("e500-pcihost", MPC8544_PCI_REGS_BASE,
513 mpic[pci_irq_nrs[0]], mpic[pci_irq_nrs[1]],
514 mpic[pci_irq_nrs[2]], mpic[pci_irq_nrs[3]],
515 NULL);
d461e3b9 516 pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
1db09b84
AJ
517 if (!pci_bus)
518 printf("couldn't create PCI controller!\n");
519
968d683c 520 isa_mmio_init(MPC8544_PCI_IO, MPC8544_PCI_IOLEN);
1db09b84
AJ
521
522 if (pci_bus) {
1db09b84
AJ
523 /* Register network interfaces. */
524 for (i = 0; i < nb_nics; i++) {
07caea31 525 pci_nic_init_nofail(&nd_table[i], "virtio", NULL);
1db09b84
AJ
526 }
527 }
528
5c145dac
AG
529 /* Register spinning region */
530 sysbus_create_simple("e500-spin", MPC8544_SPIN_BASE, NULL);
531
1db09b84
AJ
532 /* Load kernel. */
533 if (kernel_filename) {
534 kernel_size = load_uimage(kernel_filename, &entry, &loadaddr, NULL);
535 if (kernel_size < 0) {
409dbce5
AJ
536 kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry,
537 &elf_lowaddr, NULL, 1, ELF_MACHINE, 0);
1db09b84
AJ
538 entry = elf_entry;
539 loadaddr = elf_lowaddr;
540 }
541 /* XXX try again as binary */
542 if (kernel_size < 0) {
543 fprintf(stderr, "qemu: could not load kernel '%s'\n",
544 kernel_filename);
545 exit(1);
546 }
547 }
548
549 /* Load initrd. */
550 if (initrd_filename) {
75bb6589 551 initrd_base = (kernel_size + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK;
d7585251
PB
552 initrd_size = load_image_targphys(initrd_filename, initrd_base,
553 ram_size - initrd_base);
1db09b84
AJ
554
555 if (initrd_size < 0) {
556 fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
557 initrd_filename);
558 exit(1);
559 }
560 }
561
562 /* If we're loading a kernel directly, we must load the device tree too. */
563 if (kernel_filename) {
5c145dac 564 struct boot_info *boot_info;
cba2026a 565 int dt_size;
5c145dac 566
cba2026a
AG
567 dt_base = (loadaddr + kernel_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
568 dt_size = mpc8544_load_device_tree(env, dt_base, ram_size, initrd_base,
569 initrd_size, kernel_cmdline);
570 if (dt_size < 0) {
1db09b84
AJ
571 fprintf(stderr, "couldn't load device tree\n");
572 exit(1);
573 }
574
e61c36d5 575 boot_info = env->load_info;
3b989d49
AG
576 boot_info->entry = entry;
577 boot_info->dt_base = dt_base;
cba2026a 578 boot_info->dt_size = dt_size;
1db09b84
AJ
579 }
580
3b989d49 581 if (kvm_enabled()) {
1db09b84 582 kvmppc_init();
3b989d49 583 }
1db09b84
AJ
584}
585
f80f9ec9 586static QEMUMachine mpc8544ds_machine = {
1db09b84
AJ
587 .name = "mpc8544ds",
588 .desc = "mpc8544ds",
589 .init = mpc8544ds_init,
a2a67420 590 .max_cpus = 15,
1db09b84 591};
f80f9ec9
AL
592
593static void mpc8544ds_machine_init(void)
594{
595 qemu_register_machine(&mpc8544ds_machine);
596}
597
598machine_init(mpc8544ds_machine_init);