]> git.proxmox.com Git - mirror_qemu.git/blame - hw/ppce500_mpc8544ds.c
PPC: e500: Use new SOC 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 46#define MPC8544_CCSRBAR_SIZE 0x00100000
1db09b84
AJ
47#define MPC8544_MPIC_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x40000)
48#define MPC8544_SERIAL0_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x4500)
49#define MPC8544_SERIAL1_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x4600)
50#define MPC8544_PCI_REGS_BASE (MPC8544_CCSRBAR_BASE + 0x8000)
51#define MPC8544_PCI_REGS_SIZE 0x1000
52#define MPC8544_PCI_IO 0xE1000000
53#define MPC8544_PCI_IOLEN 0x10000
b0fb8423 54#define MPC8544_UTIL_BASE (MPC8544_CCSRBAR_BASE + 0xe0000)
5c145dac 55#define MPC8544_SPIN_BASE 0xEF000000
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
e2684c0b 85static int mpc8544_load_device_tree(CPUPPCState *env,
5de6b46d 86 target_phys_addr_t addr,
7f47b41f 87 target_phys_addr_t ramsize,
5de6b46d
AG
88 target_phys_addr_t initrd_base,
89 target_phys_addr_t initrd_size,
90 const char *kernel_cmdline)
1db09b84 91{
dbf916d8 92 int ret = -1;
3b989d49 93 uint32_t mem_reg_property[] = {0, cpu_to_be32(ramsize)};
7ec632b4 94 int fdt_size;
dbf916d8 95 void *fdt;
5de6b46d 96 uint8_t hypercall[16];
911d6e7a
AG
97 uint32_t clock_freq = 400000000;
98 uint32_t tb_freq = 400000000;
621d05e3 99 int i;
51b852b7 100 char compatible[] = "MPC8544DS\0MPC85xxDS";
ebb9518a 101 char compatible_sb[] = "fsl,mpc8544-immr\0simple-bus";
51b852b7 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 234 /* XXX These should go into their respective devices' code */
ebb9518a 235 snprintf(soc, sizeof(soc), "/soc@%x", MPC8544_CCSRBAR_BASE);
5da96624
AG
236 qemu_devtree_add_subnode(fdt, soc);
237 qemu_devtree_setprop_string(fdt, soc, "device_type", "soc");
ebb9518a
AG
238 qemu_devtree_setprop(fdt, soc, "compatible", compatible_sb,
239 sizeof(compatible_sb));
5da96624
AG
240 qemu_devtree_setprop_cell(fdt, soc, "#address-cells", 1);
241 qemu_devtree_setprop_cell(fdt, soc, "#size-cells", 1);
242 qemu_devtree_setprop_cells(fdt, soc, "ranges", 0x0, MPC8544_CCSRBAR_BASE,
243 MPC8544_CCSRBAR_SIZE);
5da96624
AG
244 /* XXX should contain a reasonable value */
245 qemu_devtree_setprop_cell(fdt, soc, "bus-frequency", 0);
246
19ac9dea
AG
247 snprintf(mpic, sizeof(mpic), "%s/pic@%x", soc,
248 MPC8544_MPIC_REGS_BASE - MPC8544_CCSRBAR_BASE);
249 qemu_devtree_add_subnode(fdt, mpic);
250 qemu_devtree_setprop_string(fdt, mpic, "device_type", "open-pic");
518c7fb4 251 qemu_devtree_setprop_string(fdt, mpic, "compatible", "fsl,mpic");
19ac9dea
AG
252 qemu_devtree_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_BASE -
253 MPC8544_CCSRBAR_BASE, 0x40000);
254 qemu_devtree_setprop_cell(fdt, mpic, "#address-cells", 0);
518c7fb4 255 qemu_devtree_setprop_cell(fdt, mpic, "#interrupt-cells", 4);
19ac9dea
AG
256 mpic_ph = qemu_devtree_alloc_phandle(fdt);
257 qemu_devtree_setprop_cell(fdt, mpic, "phandle", mpic_ph);
258 qemu_devtree_setprop_cell(fdt, mpic, "linux,phandle", mpic_ph);
259 qemu_devtree_setprop(fdt, mpic, "interrupt-controller", NULL, 0);
518c7fb4
AG
260 qemu_devtree_setprop(fdt, mpic, "big-endian", NULL, 0);
261 qemu_devtree_setprop(fdt, mpic, "single-cpu-affinity", NULL, 0);
262 qemu_devtree_setprop_cell(fdt, mpic, "last-interrupt-source", 255);
19ac9dea 263
0cfc6e8d
AG
264 /*
265 * We have to generate ser1 first, because Linux takes the first
266 * device it finds in the dt as serial output device. And we generate
267 * devices in reverse order to the dt.
268 */
269 snprintf(ser1, sizeof(ser1), "%s/serial@%x", soc,
270 MPC8544_SERIAL1_REGS_BASE - MPC8544_CCSRBAR_BASE);
271 qemu_devtree_add_subnode(fdt, ser1);
272 qemu_devtree_setprop_string(fdt, ser1, "device_type", "serial");
273 qemu_devtree_setprop_string(fdt, ser1, "compatible", "ns16550");
274 qemu_devtree_setprop_cells(fdt, ser1, "reg", MPC8544_SERIAL1_REGS_BASE -
275 MPC8544_CCSRBAR_BASE, 0x100);
276 qemu_devtree_setprop_cell(fdt, ser1, "cell-index", 1);
277 qemu_devtree_setprop_cell(fdt, ser1, "clock-frequency", 0);
518c7fb4 278 qemu_devtree_setprop_cells(fdt, ser1, "interrupts", 42, 2, 0, 0);
0cfc6e8d
AG
279 qemu_devtree_setprop_phandle(fdt, ser1, "interrupt-parent", mpic);
280 qemu_devtree_setprop_string(fdt, "/aliases", "serial1", ser1);
281
282 snprintf(ser0, sizeof(ser0), "%s/serial@%x", soc,
283 MPC8544_SERIAL0_REGS_BASE - MPC8544_CCSRBAR_BASE);
284 qemu_devtree_add_subnode(fdt, ser0);
285 qemu_devtree_setprop_string(fdt, ser0, "device_type", "serial");
286 qemu_devtree_setprop_string(fdt, ser0, "compatible", "ns16550");
287 qemu_devtree_setprop_cells(fdt, ser0, "reg", MPC8544_SERIAL0_REGS_BASE -
288 MPC8544_CCSRBAR_BASE, 0x100);
289 qemu_devtree_setprop_cell(fdt, ser0, "cell-index", 0);
290 qemu_devtree_setprop_cell(fdt, ser0, "clock-frequency", 0);
518c7fb4 291 qemu_devtree_setprop_cells(fdt, ser0, "interrupts", 42, 2, 0, 0);
0cfc6e8d
AG
292 qemu_devtree_setprop_phandle(fdt, ser0, "interrupt-parent", mpic);
293 qemu_devtree_setprop_string(fdt, "/aliases", "serial0", ser0);
294 qemu_devtree_setprop_string(fdt, "/chosen", "linux,stdout-path", ser0);
295
f5038483
AG
296 snprintf(gutil, sizeof(gutil), "%s/global-utilities@%x", soc,
297 MPC8544_UTIL_BASE - MPC8544_CCSRBAR_BASE);
298 qemu_devtree_add_subnode(fdt, gutil);
299 qemu_devtree_setprop_string(fdt, gutil, "compatible", "fsl,mpc8544-guts");
300 qemu_devtree_setprop_cells(fdt, gutil, "reg", MPC8544_UTIL_BASE -
301 MPC8544_CCSRBAR_BASE, 0x1000);
302 qemu_devtree_setprop(fdt, gutil, "fsl,has-rstcr", NULL, 0);
303
0dbc0798
AG
304 snprintf(pci, sizeof(pci), "/pci@%x", MPC8544_PCI_REGS_BASE);
305 qemu_devtree_add_subnode(fdt, pci);
306 qemu_devtree_setprop_cell(fdt, pci, "cell-index", 0);
307 qemu_devtree_setprop_string(fdt, pci, "compatible", "fsl,mpc8540-pci");
308 qemu_devtree_setprop_string(fdt, pci, "device_type", "pci");
309 qemu_devtree_setprop_cells(fdt, pci, "interrupt-map-mask", 0xf800, 0x0,
310 0x0, 0x7);
311 pci_map_create(fdt, pci_map, qemu_devtree_get_phandle(fdt, mpic));
312 qemu_devtree_setprop(fdt, pci, "interrupt-map", pci_map, sizeof(pci_map));
313 qemu_devtree_setprop_phandle(fdt, pci, "interrupt-parent", mpic);
518c7fb4 314 qemu_devtree_setprop_cells(fdt, pci, "interrupts", 24, 2, 0, 0);
0dbc0798
AG
315 qemu_devtree_setprop_cells(fdt, pci, "bus-range", 0, 255);
316 for (i = 0; i < 12; i++) {
317 pci_ranges[i] = cpu_to_be32(pci_ranges[i]);
318 }
319 qemu_devtree_setprop(fdt, pci, "ranges", pci_ranges, sizeof(pci_ranges));
320 qemu_devtree_setprop_cells(fdt, pci, "reg", MPC8544_PCI_REGS_BASE,
321 0x1000);
322 qemu_devtree_setprop_cell(fdt, pci, "clock-frequency", 66666666);
323 qemu_devtree_setprop_cell(fdt, pci, "#interrupt-cells", 1);
324 qemu_devtree_setprop_cell(fdt, pci, "#size-cells", 2);
325 qemu_devtree_setprop_cell(fdt, pci, "#address-cells", 3);
326 qemu_devtree_setprop_string(fdt, "/aliases", "pci0", pci);
327
d1b93565 328done:
25b42708
AG
329 if (dumpdtb) {
330 /* Dump the dtb to a file and quit */
331 FILE *f = fopen(dumpdtb, "wb");
332 size_t len;
333 len = fwrite(fdt, fdt_size, 1, f);
334 fclose(f);
335 if (len != fdt_size) {
336 exit(1);
337 }
338 exit(0);
339 }
340
04088adb 341 ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
cba2026a
AG
342 if (ret < 0) {
343 goto out;
344 }
7267c094 345 g_free(fdt);
cba2026a 346 ret = fdt_size;
7ec632b4 347
1db09b84 348out:
1db09b84 349
04088adb 350 return ret;
1db09b84
AJ
351}
352
cba2026a 353/* Create -kernel TLB entries for BookE. */
d1e256fe
AG
354static inline target_phys_addr_t booke206_page_size_to_tlb(uint64_t size)
355{
cba2026a 356 return 63 - clz64(size >> 10);
d1e256fe
AG
357}
358
cba2026a 359static void mmubooke_create_initial_mapping(CPUPPCState *env)
3b989d49 360{
cba2026a 361 struct boot_info *bi = env->load_info;
d1e256fe 362 ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0);
cba2026a
AG
363 target_phys_addr_t size, dt_end;
364 int ps;
365
366 /* Our initial TLB entry needs to cover everything from 0 to
367 the device tree top */
368 dt_end = bi->dt_base + bi->dt_size;
369 ps = booke206_page_size_to_tlb(dt_end) + 1;
370 size = (ps << MAS1_TSIZE_SHIFT);
d1e256fe 371 tlb->mas1 = MAS1_VALID | size;
cba2026a
AG
372 tlb->mas2 = 0;
373 tlb->mas7_3 = 0;
d1e256fe 374 tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
93dd5e85
SW
375
376 env->tlb_dirty = true;
3b989d49
AG
377}
378
5c145dac
AG
379static void mpc8544ds_cpu_reset_sec(void *opaque)
380{
38f92da6
AF
381 PowerPCCPU *cpu = opaque;
382 CPUPPCState *env = &cpu->env;
5c145dac 383
38f92da6 384 cpu_reset(CPU(cpu));
5c145dac
AG
385
386 /* Secondary CPU starts in halted state for now. Needs to change when
387 implementing non-kernel boot. */
388 env->halted = 1;
389 env->exception_index = EXCP_HLT;
3b989d49
AG
390}
391
392static void mpc8544ds_cpu_reset(void *opaque)
393{
38f92da6
AF
394 PowerPCCPU *cpu = opaque;
395 CPUPPCState *env = &cpu->env;
3b989d49
AG
396 struct boot_info *bi = env->load_info;
397
38f92da6 398 cpu_reset(CPU(cpu));
3b989d49
AG
399
400 /* Set initial guest state. */
5c145dac 401 env->halted = 0;
3b989d49
AG
402 env->gpr[1] = (16<<20) - 8;
403 env->gpr[3] = bi->dt_base;
404 env->nip = bi->entry;
cba2026a 405 mmubooke_create_initial_mapping(env);
3b989d49
AG
406}
407
c227f099 408static void mpc8544ds_init(ram_addr_t ram_size,
1db09b84
AJ
409 const char *boot_device,
410 const char *kernel_filename,
411 const char *kernel_cmdline,
412 const char *initrd_filename,
413 const char *cpu_model)
414{
39186d8a 415 MemoryRegion *address_space_mem = get_system_memory();
2646c133 416 MemoryRegion *ram = g_new(MemoryRegion, 1);
1db09b84 417 PCIBus *pci_bus;
e2684c0b 418 CPUPPCState *env = NULL;
1db09b84
AJ
419 uint64_t elf_entry;
420 uint64_t elf_lowaddr;
c227f099
AL
421 target_phys_addr_t entry=0;
422 target_phys_addr_t loadaddr=UIMAGE_LOAD_BASE;
1db09b84 423 target_long kernel_size=0;
75bb6589
LY
424 target_ulong dt_base = 0;
425 target_ulong initrd_base = 0;
1db09b84 426 target_long initrd_size=0;
1db09b84
AJ
427 int i=0;
428 unsigned int pci_irq_nrs[4] = {1, 2, 3, 4};
a915249f 429 qemu_irq **irqs, *mpic;
be13cc7a 430 DeviceState *dev;
e2684c0b 431 CPUPPCState *firstenv = NULL;
1db09b84 432
e61c36d5 433 /* Setup CPUs */
ef250db6
AG
434 if (cpu_model == NULL) {
435 cpu_model = "e500v2_v30";
436 }
437
a915249f
AG
438 irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *));
439 irqs[0] = g_malloc0(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
e61c36d5 440 for (i = 0; i < smp_cpus; i++) {
397b457d 441 PowerPCCPU *cpu;
e61c36d5 442 qemu_irq *input;
397b457d
AF
443
444 cpu = cpu_ppc_init(cpu_model);
445 if (cpu == NULL) {
e61c36d5
AG
446 fprintf(stderr, "Unable to initialize CPU!\n");
447 exit(1);
448 }
397b457d 449 env = &cpu->env;
1db09b84 450
e61c36d5
AG
451 if (!firstenv) {
452 firstenv = env;
453 }
1db09b84 454
a915249f
AG
455 irqs[i] = irqs[0] + (i * OPENPIC_OUTPUT_NB);
456 input = (qemu_irq *)env->irq_inputs;
457 irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT];
458 irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT];
e61c36d5 459 env->spr[SPR_BOOKE_PIR] = env->cpu_index = i;
3b989d49 460
ddd1055b 461 ppc_booke_timers_init(env, 400000000, PPC_TIMER_E500);
e61c36d5
AG
462
463 /* Register reset handler */
5c145dac
AG
464 if (!i) {
465 /* Primary CPU */
466 struct boot_info *boot_info;
467 boot_info = g_malloc0(sizeof(struct boot_info));
38f92da6 468 qemu_register_reset(mpc8544ds_cpu_reset, cpu);
5c145dac
AG
469 env->load_info = boot_info;
470 } else {
471 /* Secondary CPUs */
38f92da6 472 qemu_register_reset(mpc8544ds_cpu_reset_sec, cpu);
5c145dac 473 }
e61c36d5 474 }
3b989d49 475
e61c36d5 476 env = firstenv;
3b989d49 477
1db09b84
AJ
478 /* Fixup Memory size on a alignment boundary */
479 ram_size &= ~(RAM_SIZES_ALIGN - 1);
480
481 /* Register Memory */
c5705a77
AK
482 memory_region_init_ram(ram, "mpc8544ds.ram", ram_size);
483 vmstate_register_ram_global(ram);
2646c133 484 memory_region_add_subregion(address_space_mem, 0, ram);
1db09b84
AJ
485
486 /* MPIC */
df2921d3
AK
487 mpic = mpic_init(address_space_mem, MPC8544_MPIC_REGS_BASE,
488 smp_cpus, irqs, NULL);
a915249f
AG
489
490 if (!mpic) {
491 cpu_abort(env, "MPIC failed to initialize\n");
492 }
1db09b84
AJ
493
494 /* Serial */
2d48377a 495 if (serial_hds[0]) {
39186d8a 496 serial_mm_init(address_space_mem, MPC8544_SERIAL0_REGS_BASE,
49a2942d 497 0, mpic[12+26], 399193,
2ff0c7c3 498 serial_hds[0], DEVICE_BIG_ENDIAN);
2d48377a 499 }
1db09b84 500
2d48377a 501 if (serial_hds[1]) {
39186d8a 502 serial_mm_init(address_space_mem, MPC8544_SERIAL1_REGS_BASE,
49a2942d 503 0, mpic[12+26], 399193,
2ff0c7c3 504 serial_hds[0], DEVICE_BIG_ENDIAN);
2d48377a 505 }
1db09b84 506
b0fb8423
AG
507 /* General Utility device */
508 sysbus_create_simple("mpc8544-guts", MPC8544_UTIL_BASE, NULL);
509
1db09b84 510 /* PCI */
be13cc7a
AG
511 dev = sysbus_create_varargs("e500-pcihost", MPC8544_PCI_REGS_BASE,
512 mpic[pci_irq_nrs[0]], mpic[pci_irq_nrs[1]],
513 mpic[pci_irq_nrs[2]], mpic[pci_irq_nrs[3]],
514 NULL);
d461e3b9 515 pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
1db09b84
AJ
516 if (!pci_bus)
517 printf("couldn't create PCI controller!\n");
518
968d683c 519 isa_mmio_init(MPC8544_PCI_IO, MPC8544_PCI_IOLEN);
1db09b84
AJ
520
521 if (pci_bus) {
1db09b84
AJ
522 /* Register network interfaces. */
523 for (i = 0; i < nb_nics; i++) {
07caea31 524 pci_nic_init_nofail(&nd_table[i], "virtio", NULL);
1db09b84
AJ
525 }
526 }
527
5c145dac
AG
528 /* Register spinning region */
529 sysbus_create_simple("e500-spin", MPC8544_SPIN_BASE, NULL);
530
1db09b84
AJ
531 /* Load kernel. */
532 if (kernel_filename) {
533 kernel_size = load_uimage(kernel_filename, &entry, &loadaddr, NULL);
534 if (kernel_size < 0) {
409dbce5
AJ
535 kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry,
536 &elf_lowaddr, NULL, 1, ELF_MACHINE, 0);
1db09b84
AJ
537 entry = elf_entry;
538 loadaddr = elf_lowaddr;
539 }
540 /* XXX try again as binary */
541 if (kernel_size < 0) {
542 fprintf(stderr, "qemu: could not load kernel '%s'\n",
543 kernel_filename);
544 exit(1);
545 }
546 }
547
548 /* Load initrd. */
549 if (initrd_filename) {
75bb6589 550 initrd_base = (kernel_size + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK;
d7585251
PB
551 initrd_size = load_image_targphys(initrd_filename, initrd_base,
552 ram_size - initrd_base);
1db09b84
AJ
553
554 if (initrd_size < 0) {
555 fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
556 initrd_filename);
557 exit(1);
558 }
559 }
560
561 /* If we're loading a kernel directly, we must load the device tree too. */
562 if (kernel_filename) {
5c145dac 563 struct boot_info *boot_info;
cba2026a 564 int dt_size;
5c145dac 565
cba2026a
AG
566 dt_base = (loadaddr + kernel_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
567 dt_size = mpc8544_load_device_tree(env, dt_base, ram_size, initrd_base,
568 initrd_size, kernel_cmdline);
569 if (dt_size < 0) {
1db09b84
AJ
570 fprintf(stderr, "couldn't load device tree\n");
571 exit(1);
572 }
573
e61c36d5 574 boot_info = env->load_info;
3b989d49
AG
575 boot_info->entry = entry;
576 boot_info->dt_base = dt_base;
cba2026a 577 boot_info->dt_size = dt_size;
1db09b84
AJ
578 }
579
3b989d49 580 if (kvm_enabled()) {
1db09b84 581 kvmppc_init();
3b989d49 582 }
1db09b84
AJ
583}
584
f80f9ec9 585static QEMUMachine mpc8544ds_machine = {
1db09b84
AJ
586 .name = "mpc8544ds",
587 .desc = "mpc8544ds",
588 .init = mpc8544ds_init,
a2a67420 589 .max_cpus = 15,
1db09b84 590};
f80f9ec9
AL
591
592static void mpc8544ds_machine_init(void)
593{
594 qemu_register_machine(&mpc8544ds_machine);
595}
596
597machine_init(mpc8544ds_machine_init);