]> git.proxmox.com Git - qemu.git/blame - hw/ppce500_mpc8544ds.c
Merge remote-tracking branch 'sstabellini/compile-xs' into staging
[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;
2a7a47fc 472 env->mpic_cpu_base = MPC8544_MPIC_REGS_BASE + 0x20000;
3b989d49 473
ddd1055b 474 ppc_booke_timers_init(env, 400000000, PPC_TIMER_E500);
e61c36d5
AG
475
476 /* Register reset handler */
5c145dac
AG
477 if (!i) {
478 /* Primary CPU */
479 struct boot_info *boot_info;
480 boot_info = g_malloc0(sizeof(struct boot_info));
38f92da6 481 qemu_register_reset(mpc8544ds_cpu_reset, cpu);
5c145dac
AG
482 env->load_info = boot_info;
483 } else {
484 /* Secondary CPUs */
38f92da6 485 qemu_register_reset(mpc8544ds_cpu_reset_sec, cpu);
5c145dac 486 }
e61c36d5 487 }
3b989d49 488
e61c36d5 489 env = firstenv;
3b989d49 490
1db09b84
AJ
491 /* Fixup Memory size on a alignment boundary */
492 ram_size &= ~(RAM_SIZES_ALIGN - 1);
493
494 /* Register Memory */
c5705a77
AK
495 memory_region_init_ram(ram, "mpc8544ds.ram", ram_size);
496 vmstate_register_ram_global(ram);
2646c133 497 memory_region_add_subregion(address_space_mem, 0, ram);
1db09b84
AJ
498
499 /* MPIC */
df2921d3
AK
500 mpic = mpic_init(address_space_mem, MPC8544_MPIC_REGS_BASE,
501 smp_cpus, irqs, NULL);
a915249f
AG
502
503 if (!mpic) {
504 cpu_abort(env, "MPIC failed to initialize\n");
505 }
1db09b84
AJ
506
507 /* Serial */
2d48377a 508 if (serial_hds[0]) {
39186d8a 509 serial_mm_init(address_space_mem, MPC8544_SERIAL0_REGS_BASE,
49a2942d 510 0, mpic[12+26], 399193,
2ff0c7c3 511 serial_hds[0], DEVICE_BIG_ENDIAN);
2d48377a 512 }
1db09b84 513
2d48377a 514 if (serial_hds[1]) {
39186d8a 515 serial_mm_init(address_space_mem, MPC8544_SERIAL1_REGS_BASE,
49a2942d 516 0, mpic[12+26], 399193,
2ff0c7c3 517 serial_hds[0], DEVICE_BIG_ENDIAN);
2d48377a 518 }
1db09b84 519
b0fb8423
AG
520 /* General Utility device */
521 sysbus_create_simple("mpc8544-guts", MPC8544_UTIL_BASE, NULL);
522
1db09b84 523 /* PCI */
be13cc7a
AG
524 dev = sysbus_create_varargs("e500-pcihost", MPC8544_PCI_REGS_BASE,
525 mpic[pci_irq_nrs[0]], mpic[pci_irq_nrs[1]],
526 mpic[pci_irq_nrs[2]], mpic[pci_irq_nrs[3]],
527 NULL);
d461e3b9 528 pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
1db09b84
AJ
529 if (!pci_bus)
530 printf("couldn't create PCI controller!\n");
531
968d683c 532 isa_mmio_init(MPC8544_PCI_IO, MPC8544_PCI_IOLEN);
1db09b84
AJ
533
534 if (pci_bus) {
1db09b84
AJ
535 /* Register network interfaces. */
536 for (i = 0; i < nb_nics; i++) {
07caea31 537 pci_nic_init_nofail(&nd_table[i], "virtio", NULL);
1db09b84
AJ
538 }
539 }
540
5c145dac
AG
541 /* Register spinning region */
542 sysbus_create_simple("e500-spin", MPC8544_SPIN_BASE, NULL);
543
1db09b84
AJ
544 /* Load kernel. */
545 if (kernel_filename) {
546 kernel_size = load_uimage(kernel_filename, &entry, &loadaddr, NULL);
547 if (kernel_size < 0) {
409dbce5
AJ
548 kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry,
549 &elf_lowaddr, NULL, 1, ELF_MACHINE, 0);
1db09b84
AJ
550 entry = elf_entry;
551 loadaddr = elf_lowaddr;
552 }
553 /* XXX try again as binary */
554 if (kernel_size < 0) {
555 fprintf(stderr, "qemu: could not load kernel '%s'\n",
556 kernel_filename);
557 exit(1);
558 }
559 }
560
561 /* Load initrd. */
562 if (initrd_filename) {
75bb6589 563 initrd_base = (kernel_size + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK;
d7585251
PB
564 initrd_size = load_image_targphys(initrd_filename, initrd_base,
565 ram_size - initrd_base);
1db09b84
AJ
566
567 if (initrd_size < 0) {
568 fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
569 initrd_filename);
570 exit(1);
571 }
572 }
573
574 /* If we're loading a kernel directly, we must load the device tree too. */
575 if (kernel_filename) {
5c145dac 576 struct boot_info *boot_info;
cba2026a 577 int dt_size;
5c145dac 578
cba2026a
AG
579 dt_base = (loadaddr + kernel_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
580 dt_size = mpc8544_load_device_tree(env, dt_base, ram_size, initrd_base,
581 initrd_size, kernel_cmdline);
582 if (dt_size < 0) {
1db09b84
AJ
583 fprintf(stderr, "couldn't load device tree\n");
584 exit(1);
585 }
586
e61c36d5 587 boot_info = env->load_info;
3b989d49
AG
588 boot_info->entry = entry;
589 boot_info->dt_base = dt_base;
cba2026a 590 boot_info->dt_size = dt_size;
1db09b84
AJ
591 }
592
3b989d49 593 if (kvm_enabled()) {
1db09b84 594 kvmppc_init();
3b989d49 595 }
1db09b84
AJ
596}
597
f80f9ec9 598static QEMUMachine mpc8544ds_machine = {
1db09b84
AJ
599 .name = "mpc8544ds",
600 .desc = "mpc8544ds",
601 .init = mpc8544ds_init,
a2a67420 602 .max_cpus = 15,
1db09b84 603};
f80f9ec9
AL
604
605static void mpc8544ds_machine_init(void)
606{
607 qemu_register_machine(&mpc8544ds_machine);
608}
609
610machine_init(mpc8544ds_machine_init);