Statistics
| Branch: | Revision:

root / hw / ppce500_mpc8544ds.c @ 0cfc6e8d

History | View | Annotate | Download (16.8 kB)

1
/*
2
 * QEMU PowerPC MPC8544DS board emulation
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

    
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"
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"
29
#include "ppc.h"
30
#include "loader.h"
31
#include "elf.h"
32
#include "sysbus.h"
33
#include "exec-memory.h"
34
#include "host-utils.h"
35

    
36
#define BINARY_DEVICE_TREE_FILE    "mpc8544ds.dtb"
37
#define UIMAGE_LOAD_BASE           0
38
#define DTC_LOAD_PAD               0x500000
39
#define DTC_PAD_MASK               0xFFFFF
40
#define INITRD_LOAD_PAD            0x2000000
41
#define INITRD_PAD_MASK            0xFFFFFF
42

    
43
#define RAM_SIZES_ALIGN            (64UL << 20)
44

    
45
#define MPC8544_CCSRBAR_BASE       0xE0000000
46
#define MPC8544_CCSRBAR_REGSIZE    0x00001000
47
#define MPC8544_CCSRBAR_SIZE       0x00100000
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
55
#define MPC8544_UTIL_BASE          (MPC8544_CCSRBAR_BASE + 0xe0000)
56
#define MPC8544_SPIN_BASE          0xEF000000
57

    
58
struct boot_info
59
{
60
    uint32_t dt_base;
61
    uint32_t dt_size;
62
    uint32_t entry;
63
};
64

    
65
static int mpc8544_load_device_tree(CPUPPCState *env,
66
                                    target_phys_addr_t addr,
67
                                    uint32_t ramsize,
68
                                    target_phys_addr_t initrd_base,
69
                                    target_phys_addr_t initrd_size,
70
                                    const char *kernel_cmdline)
71
{
72
    int ret = -1;
73
    uint32_t mem_reg_property[] = {0, cpu_to_be32(ramsize)};
74
    char *filename;
75
    int fdt_size;
76
    void *fdt;
77
    uint8_t hypercall[16];
78
    uint32_t clock_freq = 400000000;
79
    uint32_t tb_freq = 400000000;
80
    int i;
81
    char compatible[] = "MPC8544DS\0MPC85xxDS";
82
    char model[] = "MPC8544DS";
83
    char soc[128];
84
    char ser0[128];
85
    char ser1[128];
86

    
87
    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
88
    if (!filename) {
89
        goto out;
90
    }
91
    fdt = load_device_tree(filename, &fdt_size);
92
    g_free(filename);
93
    if (fdt == NULL) {
94
        goto out;
95
    }
96

    
97
    /* Manipulate device tree in memory. */
98
    qemu_devtree_setprop_string(fdt, "/", "model", model);
99
    qemu_devtree_setprop(fdt, "/", "compatible", compatible,
100
                         sizeof(compatible));
101
    qemu_devtree_setprop_cell(fdt, "/", "#address-cells", 1);
102
    qemu_devtree_setprop_cell(fdt, "/", "#size-cells", 1);
103

    
104
    qemu_devtree_add_subnode(fdt, "/memory");
105
    qemu_devtree_setprop_string(fdt, "/memory", "device_type", "memory");
106
    qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property,
107
                         sizeof(mem_reg_property));
108

    
109
    qemu_devtree_add_subnode(fdt, "/chosen");
110
    if (initrd_size) {
111
        ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start",
112
                                        initrd_base);
113
        if (ret < 0) {
114
            fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
115
        }
116

    
117
        ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end",
118
                                        (initrd_base + initrd_size));
119
        if (ret < 0) {
120
            fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
121
        }
122
    }
123

    
124
    ret = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs",
125
                                      kernel_cmdline);
126
    if (ret < 0)
127
        fprintf(stderr, "couldn't set /chosen/bootargs\n");
128

    
129
    if (kvm_enabled()) {
130
        /* Read out host's frequencies */
131
        clock_freq = kvmppc_get_clockfreq();
132
        tb_freq = kvmppc_get_tbfreq();
133

    
134
        /* indicate KVM hypercall interface */
135
        qemu_devtree_add_subnode(fdt, "/hypervisor");
136
        qemu_devtree_setprop_string(fdt, "/hypervisor", "compatible",
137
                                    "linux,kvm");
138
        kvmppc_get_hypercall(env, hypercall, sizeof(hypercall));
139
        qemu_devtree_setprop(fdt, "/hypervisor", "hcall-instructions",
140
                             hypercall, sizeof(hypercall));
141
    }
142

    
143
    /* Create CPU nodes */
144
    qemu_devtree_add_subnode(fdt, "/cpus");
145
    qemu_devtree_setprop_cell(fdt, "/cpus", "#address-cells", 1);
146
    qemu_devtree_setprop_cell(fdt, "/cpus", "#size-cells", 0);
147

    
148
    /* We need to generate the cpu nodes in reverse order, so Linux can pick
149
       the first node as boot node and be happy */
150
    for (i = smp_cpus - 1; i >= 0; i--) {
151
        char cpu_name[128];
152
        uint64_t cpu_release_addr = cpu_to_be64(MPC8544_SPIN_BASE + (i * 0x20));
153

    
154
        for (env = first_cpu; env != NULL; env = env->next_cpu) {
155
            if (env->cpu_index == i) {
156
                break;
157
            }
158
        }
159

    
160
        if (!env) {
161
            continue;
162
        }
163

    
164
        snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x", env->cpu_index);
165
        qemu_devtree_add_subnode(fdt, cpu_name);
166
        qemu_devtree_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq);
167
        qemu_devtree_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq);
168
        qemu_devtree_setprop_string(fdt, cpu_name, "device_type", "cpu");
169
        qemu_devtree_setprop_cell(fdt, cpu_name, "reg", env->cpu_index);
170
        qemu_devtree_setprop_cell(fdt, cpu_name, "d-cache-line-size",
171
                                  env->dcache_line_size);
172
        qemu_devtree_setprop_cell(fdt, cpu_name, "i-cache-line-size",
173
                                  env->icache_line_size);
174
        qemu_devtree_setprop_cell(fdt, cpu_name, "d-cache-size", 0x8000);
175
        qemu_devtree_setprop_cell(fdt, cpu_name, "i-cache-size", 0x8000);
176
        qemu_devtree_setprop_cell(fdt, cpu_name, "bus-frequency", 0);
177
        if (env->cpu_index) {
178
            qemu_devtree_setprop_string(fdt, cpu_name, "status", "disabled");
179
            qemu_devtree_setprop_string(fdt, cpu_name, "enable-method", "spin-table");
180
            qemu_devtree_setprop(fdt, cpu_name, "cpu-release-addr",
181
                                 &cpu_release_addr, sizeof(cpu_release_addr));
182
        } else {
183
            qemu_devtree_setprop_string(fdt, cpu_name, "status", "okay");
184
        }
185
    }
186

    
187
    qemu_devtree_add_subnode(fdt, "/aliases");
188
    /* XXX These should go into their respective devices' code */
189
    snprintf(soc, sizeof(soc), "/soc8544@%x", MPC8544_CCSRBAR_BASE);
190
    qemu_devtree_add_subnode(fdt, soc);
191
    qemu_devtree_setprop_string(fdt, soc, "device_type", "soc");
192
    qemu_devtree_setprop_string(fdt, soc, "compatible", "simple-bus");
193
    qemu_devtree_setprop_cell(fdt, soc, "#address-cells", 1);
194
    qemu_devtree_setprop_cell(fdt, soc, "#size-cells", 1);
195
    qemu_devtree_setprop_cells(fdt, soc, "ranges", 0x0, MPC8544_CCSRBAR_BASE,
196
                               MPC8544_CCSRBAR_SIZE);
197
    qemu_devtree_setprop_cells(fdt, soc, "reg", MPC8544_CCSRBAR_BASE,
198
                               MPC8544_CCSRBAR_REGSIZE);
199
    /* XXX should contain a reasonable value */
200
    qemu_devtree_setprop_cell(fdt, soc, "bus-frequency", 0);
201

    
202
    /*
203
     * We have to generate ser1 first, because Linux takes the first
204
     * device it finds in the dt as serial output device. And we generate
205
     * devices in reverse order to the dt.
206
     */
207
    snprintf(ser1, sizeof(ser1), "%s/serial@%x", soc,
208
             MPC8544_SERIAL1_REGS_BASE - MPC8544_CCSRBAR_BASE);
209
    qemu_devtree_add_subnode(fdt, ser1);
210
    qemu_devtree_setprop_string(fdt, ser1, "device_type", "serial");
211
    qemu_devtree_setprop_string(fdt, ser1, "compatible", "ns16550");
212
    qemu_devtree_setprop_cells(fdt, ser1, "reg", MPC8544_SERIAL1_REGS_BASE -
213
                               MPC8544_CCSRBAR_BASE, 0x100);
214
    qemu_devtree_setprop_cell(fdt, ser1, "cell-index", 1);
215
    qemu_devtree_setprop_cell(fdt, ser1, "clock-frequency", 0);
216
    qemu_devtree_setprop_cells(fdt, ser1, "interrupts", 42, 2);
217
    qemu_devtree_setprop_phandle(fdt, ser1, "interrupt-parent", mpic);
218
    qemu_devtree_setprop_string(fdt, "/aliases", "serial1", ser1);
219

    
220
    snprintf(ser0, sizeof(ser0), "%s/serial@%x", soc,
221
             MPC8544_SERIAL0_REGS_BASE - MPC8544_CCSRBAR_BASE);
222
    qemu_devtree_add_subnode(fdt, ser0);
223
    qemu_devtree_setprop_string(fdt, ser0, "device_type", "serial");
224
    qemu_devtree_setprop_string(fdt, ser0, "compatible", "ns16550");
225
    qemu_devtree_setprop_cells(fdt, ser0, "reg", MPC8544_SERIAL0_REGS_BASE -
226
                               MPC8544_CCSRBAR_BASE, 0x100);
227
    qemu_devtree_setprop_cell(fdt, ser0, "cell-index", 0);
228
    qemu_devtree_setprop_cell(fdt, ser0, "clock-frequency", 0);
229
    qemu_devtree_setprop_cells(fdt, ser0, "interrupts", 42, 2);
230
    qemu_devtree_setprop_phandle(fdt, ser0, "interrupt-parent", mpic);
231
    qemu_devtree_setprop_string(fdt, "/aliases", "serial0", ser0);
232
    qemu_devtree_setprop_string(fdt, "/chosen", "linux,stdout-path", ser0);
233

    
234
    ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
235
    if (ret < 0) {
236
        goto out;
237
    }
238
    g_free(fdt);
239
    ret = fdt_size;
240

    
241
out:
242

    
243
    return ret;
244
}
245

    
246
/* Create -kernel TLB entries for BookE.  */
247
static inline target_phys_addr_t booke206_page_size_to_tlb(uint64_t size)
248
{
249
    return 63 - clz64(size >> 10);
250
}
251

    
252
static void mmubooke_create_initial_mapping(CPUPPCState *env)
253
{
254
    struct boot_info *bi = env->load_info;
255
    ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 0);
256
    target_phys_addr_t size, dt_end;
257
    int ps;
258

    
259
    /* Our initial TLB entry needs to cover everything from 0 to
260
       the device tree top */
261
    dt_end = bi->dt_base + bi->dt_size;
262
    ps = booke206_page_size_to_tlb(dt_end) + 1;
263
    size = (ps << MAS1_TSIZE_SHIFT);
264
    tlb->mas1 = MAS1_VALID | size;
265
    tlb->mas2 = 0;
266
    tlb->mas7_3 = 0;
267
    tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
268

    
269
    env->tlb_dirty = true;
270
}
271

    
272
static void mpc8544ds_cpu_reset_sec(void *opaque)
273
{
274
    PowerPCCPU *cpu = opaque;
275
    CPUPPCState *env = &cpu->env;
276

    
277
    cpu_reset(CPU(cpu));
278

    
279
    /* Secondary CPU starts in halted state for now. Needs to change when
280
       implementing non-kernel boot. */
281
    env->halted = 1;
282
    env->exception_index = EXCP_HLT;
283
}
284

    
285
static void mpc8544ds_cpu_reset(void *opaque)
286
{
287
    PowerPCCPU *cpu = opaque;
288
    CPUPPCState *env = &cpu->env;
289
    struct boot_info *bi = env->load_info;
290

    
291
    cpu_reset(CPU(cpu));
292

    
293
    /* Set initial guest state. */
294
    env->halted = 0;
295
    env->gpr[1] = (16<<20) - 8;
296
    env->gpr[3] = bi->dt_base;
297
    env->nip = bi->entry;
298
    mmubooke_create_initial_mapping(env);
299
}
300

    
301
static void mpc8544ds_init(ram_addr_t ram_size,
302
                         const char *boot_device,
303
                         const char *kernel_filename,
304
                         const char *kernel_cmdline,
305
                         const char *initrd_filename,
306
                         const char *cpu_model)
307
{
308
    MemoryRegion *address_space_mem = get_system_memory();
309
    MemoryRegion *ram = g_new(MemoryRegion, 1);
310
    PCIBus *pci_bus;
311
    CPUPPCState *env = NULL;
312
    uint64_t elf_entry;
313
    uint64_t elf_lowaddr;
314
    target_phys_addr_t entry=0;
315
    target_phys_addr_t loadaddr=UIMAGE_LOAD_BASE;
316
    target_long kernel_size=0;
317
    target_ulong dt_base = 0;
318
    target_ulong initrd_base = 0;
319
    target_long initrd_size=0;
320
    int i=0;
321
    unsigned int pci_irq_nrs[4] = {1, 2, 3, 4};
322
    qemu_irq **irqs, *mpic;
323
    DeviceState *dev;
324
    CPUPPCState *firstenv = NULL;
325

    
326
    /* Setup CPUs */
327
    if (cpu_model == NULL) {
328
        cpu_model = "e500v2_v30";
329
    }
330

    
331
    irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *));
332
    irqs[0] = g_malloc0(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
333
    for (i = 0; i < smp_cpus; i++) {
334
        PowerPCCPU *cpu;
335
        qemu_irq *input;
336

    
337
        cpu = cpu_ppc_init(cpu_model);
338
        if (cpu == NULL) {
339
            fprintf(stderr, "Unable to initialize CPU!\n");
340
            exit(1);
341
        }
342
        env = &cpu->env;
343

    
344
        if (!firstenv) {
345
            firstenv = env;
346
        }
347

    
348
        irqs[i] = irqs[0] + (i * OPENPIC_OUTPUT_NB);
349
        input = (qemu_irq *)env->irq_inputs;
350
        irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT];
351
        irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT];
352
        env->spr[SPR_BOOKE_PIR] = env->cpu_index = i;
353

    
354
        ppc_booke_timers_init(env, 400000000, PPC_TIMER_E500);
355

    
356
        /* Register reset handler */
357
        if (!i) {
358
            /* Primary CPU */
359
            struct boot_info *boot_info;
360
            boot_info = g_malloc0(sizeof(struct boot_info));
361
            qemu_register_reset(mpc8544ds_cpu_reset, cpu);
362
            env->load_info = boot_info;
363
        } else {
364
            /* Secondary CPUs */
365
            qemu_register_reset(mpc8544ds_cpu_reset_sec, cpu);
366
        }
367
    }
368

    
369
    env = firstenv;
370

    
371
    /* Fixup Memory size on a alignment boundary */
372
    ram_size &= ~(RAM_SIZES_ALIGN - 1);
373

    
374
    /* Register Memory */
375
    memory_region_init_ram(ram, "mpc8544ds.ram", ram_size);
376
    vmstate_register_ram_global(ram);
377
    memory_region_add_subregion(address_space_mem, 0, ram);
378

    
379
    /* MPIC */
380
    mpic = mpic_init(address_space_mem, MPC8544_MPIC_REGS_BASE,
381
                     smp_cpus, irqs, NULL);
382

    
383
    if (!mpic) {
384
        cpu_abort(env, "MPIC failed to initialize\n");
385
    }
386

    
387
    /* Serial */
388
    if (serial_hds[0]) {
389
        serial_mm_init(address_space_mem, MPC8544_SERIAL0_REGS_BASE,
390
                       0, mpic[12+26], 399193,
391
                       serial_hds[0], DEVICE_BIG_ENDIAN);
392
    }
393

    
394
    if (serial_hds[1]) {
395
        serial_mm_init(address_space_mem, MPC8544_SERIAL1_REGS_BASE,
396
                       0, mpic[12+26], 399193,
397
                       serial_hds[0], DEVICE_BIG_ENDIAN);
398
    }
399

    
400
    /* General Utility device */
401
    sysbus_create_simple("mpc8544-guts", MPC8544_UTIL_BASE, NULL);
402

    
403
    /* PCI */
404
    dev = sysbus_create_varargs("e500-pcihost", MPC8544_PCI_REGS_BASE,
405
                                mpic[pci_irq_nrs[0]], mpic[pci_irq_nrs[1]],
406
                                mpic[pci_irq_nrs[2]], mpic[pci_irq_nrs[3]],
407
                                NULL);
408
    pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
409
    if (!pci_bus)
410
        printf("couldn't create PCI controller!\n");
411

    
412
    isa_mmio_init(MPC8544_PCI_IO, MPC8544_PCI_IOLEN);
413

    
414
    if (pci_bus) {
415
        /* Register network interfaces. */
416
        for (i = 0; i < nb_nics; i++) {
417
            pci_nic_init_nofail(&nd_table[i], "virtio", NULL);
418
        }
419
    }
420

    
421
    /* Register spinning region */
422
    sysbus_create_simple("e500-spin", MPC8544_SPIN_BASE, NULL);
423

    
424
    /* Load kernel. */
425
    if (kernel_filename) {
426
        kernel_size = load_uimage(kernel_filename, &entry, &loadaddr, NULL);
427
        if (kernel_size < 0) {
428
            kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry,
429
                                   &elf_lowaddr, NULL, 1, ELF_MACHINE, 0);
430
            entry = elf_entry;
431
            loadaddr = elf_lowaddr;
432
        }
433
        /* XXX try again as binary */
434
        if (kernel_size < 0) {
435
            fprintf(stderr, "qemu: could not load kernel '%s'\n",
436
                    kernel_filename);
437
            exit(1);
438
        }
439
    }
440

    
441
    /* Load initrd. */
442
    if (initrd_filename) {
443
        initrd_base = (kernel_size + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK;
444
        initrd_size = load_image_targphys(initrd_filename, initrd_base,
445
                                          ram_size - initrd_base);
446

    
447
        if (initrd_size < 0) {
448
            fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
449
                    initrd_filename);
450
            exit(1);
451
        }
452
    }
453

    
454
    /* If we're loading a kernel directly, we must load the device tree too. */
455
    if (kernel_filename) {
456
        struct boot_info *boot_info;
457
        int dt_size;
458

    
459
        dt_base = (loadaddr + kernel_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
460
        dt_size = mpc8544_load_device_tree(env, dt_base, ram_size, initrd_base,
461
                                           initrd_size, kernel_cmdline);
462
        if (dt_size < 0) {
463
            fprintf(stderr, "couldn't load device tree\n");
464
            exit(1);
465
        }
466

    
467
        boot_info = env->load_info;
468
        boot_info->entry = entry;
469
        boot_info->dt_base = dt_base;
470
        boot_info->dt_size = dt_size;
471
    }
472

    
473
    if (kvm_enabled()) {
474
        kvmppc_init();
475
    }
476
}
477

    
478
static QEMUMachine mpc8544ds_machine = {
479
    .name = "mpc8544ds",
480
    .desc = "mpc8544ds",
481
    .init = mpc8544ds_init,
482
    .max_cpus = 15,
483
};
484

    
485
static void mpc8544ds_machine_init(void)
486
{
487
    qemu_register_machine(&mpc8544ds_machine);
488
}
489

    
490
machine_init(mpc8544ds_machine_init);