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