xref: /qemu/hw/ppc/ppc440_bamboo.c (revision 36b6968d3408b779d32eedb0fb11a4b6b828a0b2)
12c9fade2Saurel32 /*
25cbdb3a3SStefan Weil  * QEMU PowerPC 440 Bamboo board emulation
32c9fade2Saurel32  *
42c9fade2Saurel32  * Copyright 2007 IBM Corporation.
52c9fade2Saurel32  * Authors:
62c9fade2Saurel32  *  Jerone Young <jyoung5@us.ibm.com>
72c9fade2Saurel32  *  Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
82c9fade2Saurel32  *  Hollis Blanchard <hollisb@us.ibm.com>
92c9fade2Saurel32  *
102c9fade2Saurel32  * This work is licensed under the GNU GPL license version 2 or later.
112c9fade2Saurel32  *
122c9fade2Saurel32  */
132c9fade2Saurel32 
140d75590dSPeter Maydell #include "qemu/osdep.h"
15ab3dd749SPhilippe Mathieu-Daudé #include "qemu/units.h"
162c65db5eSPaolo Bonzini #include "qemu/datadir.h"
1764b47457Sthuth@redhat.com #include "qemu/error-report.h"
181422e32dSPaolo Bonzini #include "net/net.h"
1983c9f4caSPaolo Bonzini #include "hw/pci/pci.h"
2083c9f4caSPaolo Bonzini #include "hw/boards.h"
219c17d615SPaolo Bonzini #include "sysemu/kvm.h"
229c17d615SPaolo Bonzini #include "sysemu/device_tree.h"
2383c9f4caSPaolo Bonzini #include "hw/loader.h"
24ca20cf32SBlue Swirl #include "elf.h"
250d09e41aSPaolo Bonzini #include "hw/char/serial.h"
260d09e41aSPaolo Bonzini #include "hw/ppc/ppc.h"
279c17d615SPaolo Bonzini #include "sysemu/sysemu.h"
2871e8a915SMarkus Armbruster #include "sysemu/reset.h"
2983c9f4caSPaolo Bonzini #include "hw/sysbus.h"
300270d74eSPeter Maydell #include "hw/intc/ppc-uic.h"
310270d74eSPeter Maydell #include "hw/qdev-properties.h"
320270d74eSPeter Maydell #include "qapi/error.h"
332c9fade2Saurel32 
348d42c851SDaniel Henrique Barboza #include <libfdt.h>
358d42c851SDaniel Henrique Barboza 
362c9fade2Saurel32 #define BINARY_DEVICE_TREE_FILE "bamboo.dtb"
372c9fade2Saurel32 
38ceee6da6SHollis Blanchard /* from u-boot */
39ceee6da6SHollis Blanchard #define KERNEL_ADDR  0x1000000
40ceee6da6SHollis Blanchard #define FDT_ADDR     0x1800000
41ceee6da6SHollis Blanchard #define RAMDISK_ADDR 0x1900000
42ceee6da6SHollis Blanchard 
433960b04dSAlexander Graf #define PPC440EP_PCI_CONFIG     0xeec00000
443960b04dSAlexander Graf #define PPC440EP_PCI_INTACK     0xeed00000
453960b04dSAlexander Graf #define PPC440EP_PCI_SPECIAL    0xeed00000
463960b04dSAlexander Graf #define PPC440EP_PCI_REGS       0xef400000
473960b04dSAlexander Graf #define PPC440EP_PCI_IO         0xe8000000
483960b04dSAlexander Graf #define PPC440EP_PCI_IOLEN      0x00010000
493960b04dSAlexander Graf 
50a8170e5eSAvi Kivity static hwaddr entry;
51b10a04b5SAlexander Graf 
528d42c851SDaniel Henrique Barboza static int bamboo_load_device_tree(MachineState *machine,
538d42c851SDaniel Henrique Barboza                                    hwaddr addr,
54a8170e5eSAvi Kivity                                    hwaddr initrd_base,
558d42c851SDaniel Henrique Barboza                                    hwaddr initrd_size)
562c9fade2Saurel32 {
57dbf916d8SAurelien Jarno     int ret = -1;
588d42c851SDaniel Henrique Barboza     uint32_t mem_reg_property[] = { 0, 0, cpu_to_be32(machine->ram_size) };
595cea8590SPaul Brook     char *filename;
607ec632b4Spbrook     int fdt_size;
61dbf916d8SAurelien Jarno     void *fdt;
627dadd40cSAlexander Graf     uint32_t tb_freq = 400000000;
637dadd40cSAlexander Graf     uint32_t clock_freq = 400000000;
642c9fade2Saurel32 
655cea8590SPaul Brook     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
665cea8590SPaul Brook     if (!filename) {
67400431efSDaniel Henrique Barboza         return -1;
685cea8590SPaul Brook     }
695cea8590SPaul Brook     fdt = load_device_tree(filename, &fdt_size);
707267c094SAnthony Liguori     g_free(filename);
715cea8590SPaul Brook     if (fdt == NULL) {
72400431efSDaniel Henrique Barboza         return -1;
735cea8590SPaul Brook     }
742c9fade2Saurel32 
752c9fade2Saurel32     /* Manipulate device tree in memory. */
762c9fade2Saurel32 
775a4348d1SPeter Crosthwaite     ret = qemu_fdt_setprop(fdt, "/memory", "reg", mem_reg_property,
782c9fade2Saurel32                            sizeof(mem_reg_property));
7995e22932SBALATON Zoltan     if (ret < 0) {
802c9fade2Saurel32         fprintf(stderr, "couldn't set /memory/reg\n");
8195e22932SBALATON Zoltan     }
825a4348d1SPeter Crosthwaite     ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start",
832c9fade2Saurel32                                 initrd_base);
8495e22932SBALATON Zoltan     if (ret < 0) {
852c9fade2Saurel32         fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
8695e22932SBALATON Zoltan     }
875a4348d1SPeter Crosthwaite     ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
882c9fade2Saurel32                                 (initrd_base + initrd_size));
8995e22932SBALATON Zoltan     if (ret < 0) {
902c9fade2Saurel32         fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
9195e22932SBALATON Zoltan     }
925a4348d1SPeter Crosthwaite     ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
938d42c851SDaniel Henrique Barboza                                   machine->kernel_cmdline);
9495e22932SBALATON Zoltan     if (ret < 0) {
952c9fade2Saurel32         fprintf(stderr, "couldn't set /chosen/bootargs\n");
9695e22932SBALATON Zoltan     }
972c9fade2Saurel32 
985a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/cpus/cpu@0", "clock-frequency",
997dadd40cSAlexander Graf                           clock_freq);
1005a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/cpus/cpu@0", "timebase-frequency",
1017dadd40cSAlexander Graf                           tb_freq);
1022c9fade2Saurel32 
103fe1479aaSMichael S. Tsirkin     rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
1048d42c851SDaniel Henrique Barboza 
1058d42c851SDaniel Henrique Barboza     /* Set ms->fdt for 'dumpdtb' QMP/HMP command */
1068d42c851SDaniel Henrique Barboza     machine->fdt = fdt;
1078d42c851SDaniel Henrique Barboza 
108fe1479aaSMichael S. Tsirkin     return 0;
1092c9fade2Saurel32 }
1102c9fade2Saurel32 
11172718e9aSAlexander Graf /* Create reset TLB entries for BookE, spanning the 32bit addr space.  */
112e2684c0bSAndreas Färber static void mmubooke_create_initial_mapping(CPUPPCState *env,
11372718e9aSAlexander Graf                                      target_ulong va,
114a8170e5eSAvi Kivity                                      hwaddr pa)
11572718e9aSAlexander Graf {
11672718e9aSAlexander Graf     ppcemb_tlb_t *tlb = &env->tlb.tlbe[0];
11772718e9aSAlexander Graf 
11872718e9aSAlexander Graf     tlb->attr = 0;
11972718e9aSAlexander Graf     tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
120a1f7f97bSPeter Maydell     tlb->size = 1U << 31; /* up to 0x80000000  */
12172718e9aSAlexander Graf     tlb->EPN = va & TARGET_PAGE_MASK;
12272718e9aSAlexander Graf     tlb->RPN = pa & TARGET_PAGE_MASK;
12372718e9aSAlexander Graf     tlb->PID = 0;
12472718e9aSAlexander Graf 
12572718e9aSAlexander Graf     tlb = &env->tlb.tlbe[1];
12672718e9aSAlexander Graf     tlb->attr = 0;
12772718e9aSAlexander Graf     tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
128a1f7f97bSPeter Maydell     tlb->size = 1U << 31; /* up to 0xffffffff  */
12972718e9aSAlexander Graf     tlb->EPN = 0x80000000 & TARGET_PAGE_MASK;
13072718e9aSAlexander Graf     tlb->RPN = 0x80000000 & TARGET_PAGE_MASK;
13172718e9aSAlexander Graf     tlb->PID = 0;
13272718e9aSAlexander Graf }
13372718e9aSAlexander Graf 
134b10a04b5SAlexander Graf static void main_cpu_reset(void *opaque)
135b10a04b5SAlexander Graf {
136182fbbf2SAndreas Färber     PowerPCCPU *cpu = opaque;
137182fbbf2SAndreas Färber     CPUPPCState *env = &cpu->env;
138b10a04b5SAlexander Graf 
139182fbbf2SAndreas Färber     cpu_reset(CPU(cpu));
140ab3dd749SPhilippe Mathieu-Daudé     env->gpr[1] = (16 * MiB) - 8;
141b10a04b5SAlexander Graf     env->gpr[3] = FDT_ADDR;
142b10a04b5SAlexander Graf     env->nip = entry;
14372718e9aSAlexander Graf 
14472718e9aSAlexander Graf     /* Create a mapping for the kernel.  */
14572718e9aSAlexander Graf     mmubooke_create_initial_mapping(env, 0, 0);
146b10a04b5SAlexander Graf }
147b10a04b5SAlexander Graf 
1483ef96221SMarcel Apfelbaum static void bamboo_init(MachineState *machine)
1492c9fade2Saurel32 {
1503ef96221SMarcel Apfelbaum     const char *kernel_filename = machine->kernel_filename;
1513ef96221SMarcel Apfelbaum     const char *initrd_filename = machine->initrd_filename;
152053b7086SThomas Huth     MachineClass *mc = MACHINE_GET_CLASS(machine);
1532c9fade2Saurel32     unsigned int pci_irq_nrs[4] = { 28, 27, 26, 25 };
1543e9f0113SRichard Henderson     MemoryRegion *address_space_mem = get_system_memory();
15568501502SPaolo Bonzini     MemoryRegion *isa = g_new(MemoryRegion, 1);
1562c9fade2Saurel32     PCIBus *pcibus;
157322164e0SAndreas Färber     PowerPCCPU *cpu;
158e2684c0bSAndreas Färber     CPUPPCState *env;
1592c9fade2Saurel32     target_long initrd_size = 0;
16034ba1dc8SAlexander Graf     DeviceState *dev;
1610270d74eSPeter Maydell     DeviceState *uicdev;
1620270d74eSPeter Maydell     SysBusDevice *uicsbd;
163ceee6da6SHollis Blanchard     int success;
1642c9fade2Saurel32 
16574b2fd63SCédric Le Goater     if (kvm_enabled()) {
16674b2fd63SCédric Le Goater         error_report("machine %s does not support the KVM accelerator",
16774b2fd63SCédric Le Goater                      MACHINE_GET_CLASS(machine)->name);
16874b2fd63SCédric Le Goater         exit(EXIT_FAILURE);
16974b2fd63SCédric Le Goater     }
17074b2fd63SCédric Le Goater 
171376d7a2aSIgor Mammedov     cpu = POWERPC_CPU(cpu_create(machine->cpu_type));
172322164e0SAndreas Färber     env = &cpu->env;
17334ba1dc8SAlexander Graf 
17400469dc3SValentin Plotkin     if (env->mmu_model != POWERPC_MMU_BOOKE) {
1756f76b817SAlistair Francis         error_report("MMU model %i not supported by this machine",
17600469dc3SValentin Plotkin                      env->mmu_model);
17700469dc3SValentin Plotkin         exit(1);
17800469dc3SValentin Plotkin     }
17900469dc3SValentin Plotkin 
180182fbbf2SAndreas Färber     qemu_register_reset(main_cpu_reset, cpu);
181a34a92b9SAndreas Färber     ppc_booke_timers_init(cpu, 400000000, 0);
18234ba1dc8SAlexander Graf     ppc_dcr_init(env, NULL, NULL);
18334ba1dc8SAlexander Graf 
18434ba1dc8SAlexander Graf     /* interrupt controller */
1850270d74eSPeter Maydell     uicdev = qdev_new(TYPE_PPC_UIC);
186a55b2136SBALATON Zoltan     ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(uicdev), cpu, &error_fatal);
187a55b2136SBALATON Zoltan     object_unref(OBJECT(uicdev));
1880270d74eSPeter Maydell     uicsbd = SYS_BUS_DEVICE(uicdev);
1890270d74eSPeter Maydell     sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_INT,
19047b60fc6SCédric Le Goater                        qdev_get_gpio_in(DEVICE(cpu), PPC40x_INPUT_INT));
1910270d74eSPeter Maydell     sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_CINT,
19247b60fc6SCédric Le Goater                        qdev_get_gpio_in(DEVICE(cpu), PPC40x_INPUT_CINT));
19334ba1dc8SAlexander Graf 
19434ba1dc8SAlexander Graf     /* SDRAM controller */
1954fc30e15SBALATON Zoltan     dev = qdev_new(TYPE_PPC4xx_SDRAM_DDR);
1964fc30e15SBALATON Zoltan     object_property_set_link(OBJECT(dev), "dram", OBJECT(machine->ram),
1974fc30e15SBALATON Zoltan                              &error_abort);
1984fc30e15SBALATON Zoltan     ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(dev), cpu, &error_fatal);
1994fc30e15SBALATON Zoltan     object_unref(OBJECT(dev));
20034ba1dc8SAlexander Graf     /* XXX 440EP's ECC interrupts are on UIC1, but we've only created UIC0. */
2014fc30e15SBALATON Zoltan     sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(uicdev, 14));
20268b9a2e3SBALATON Zoltan     /* Enable SDRAM memory regions, this should be done by the firmware */
2031e545fbcSBALATON Zoltan     ppc4xx_sdram_ddr_enable(PPC4xx_SDRAM_DDR(dev));
20434ba1dc8SAlexander Graf 
20534ba1dc8SAlexander Graf     /* PCI */
206e75a951bSBALATON Zoltan     dev = sysbus_create_varargs(TYPE_PPC4xx_PCI_HOST, PPC440EP_PCI_CONFIG,
2070270d74eSPeter Maydell                                 qdev_get_gpio_in(uicdev, pci_irq_nrs[0]),
2080270d74eSPeter Maydell                                 qdev_get_gpio_in(uicdev, pci_irq_nrs[1]),
2090270d74eSPeter Maydell                                 qdev_get_gpio_in(uicdev, pci_irq_nrs[2]),
2100270d74eSPeter Maydell                                 qdev_get_gpio_in(uicdev, pci_irq_nrs[3]),
21134ba1dc8SAlexander Graf                                 NULL);
21234ba1dc8SAlexander Graf     pcibus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
21334ba1dc8SAlexander Graf     if (!pcibus) {
2146f76b817SAlistair Francis         error_report("couldn't create PCI controller");
21534ba1dc8SAlexander Graf         exit(1);
21634ba1dc8SAlexander Graf     }
21734ba1dc8SAlexander Graf 
21868501502SPaolo Bonzini     memory_region_init_alias(isa, NULL, "isa_mmio",
21968501502SPaolo Bonzini                              get_system_io(), 0, PPC440EP_PCI_IOLEN);
22068501502SPaolo Bonzini     memory_region_add_subregion(get_system_memory(), PPC440EP_PCI_IO, isa);
22134ba1dc8SAlexander Graf 
2229bca0edbSPeter Maydell     if (serial_hd(0) != NULL) {
2230270d74eSPeter Maydell         serial_mm_init(address_space_mem, 0xef600300, 0,
2240270d74eSPeter Maydell                        qdev_get_gpio_in(uicdev, 0),
2259bca0edbSPeter Maydell                        PPC_SERIAL_MM_BAUDBASE, serial_hd(0),
22634ba1dc8SAlexander Graf                        DEVICE_BIG_ENDIAN);
22734ba1dc8SAlexander Graf     }
2289bca0edbSPeter Maydell     if (serial_hd(1) != NULL) {
2290270d74eSPeter Maydell         serial_mm_init(address_space_mem, 0xef600400, 0,
2300270d74eSPeter Maydell                        qdev_get_gpio_in(uicdev, 1),
2319bca0edbSPeter Maydell                        PPC_SERIAL_MM_BAUDBASE, serial_hd(1),
23234ba1dc8SAlexander Graf                        DEVICE_BIG_ENDIAN);
23334ba1dc8SAlexander Graf     }
2342c9fade2Saurel32 
2352c9fade2Saurel32     if (pcibus) {
23695e22932SBALATON Zoltan         /*
23795e22932SBALATON Zoltan          * There are no PCI NICs on the Bamboo board, but there are
23895e22932SBALATON Zoltan          * PCI slots, so we can pick whatever default model we want.
23995e22932SBALATON Zoltan          */
240*36b6968dSDavid Woodhouse         pci_init_nic_devices(pcibus, mc->default_nic);
2412c9fade2Saurel32     }
2422c9fade2Saurel32 
2432c9fade2Saurel32     /* Load kernel. */
2442c9fade2Saurel32     if (kernel_filename) {
245617160c9SBALATON Zoltan         hwaddr loadaddr = LOAD_UIMAGE_LOADADDR_INVALID;
24625bda50aSMax Filippov         success = load_uimage(kernel_filename, &entry, &loadaddr, NULL,
24725bda50aSMax Filippov                               NULL, NULL);
248ceee6da6SHollis Blanchard         if (success < 0) {
249617160c9SBALATON Zoltan             uint64_t elf_entry;
2504366e1dbSLiam Merwick             success = load_elf(kernel_filename, NULL, NULL, NULL, &elf_entry,
251617160c9SBALATON Zoltan                                NULL, NULL, NULL, 1, PPC_ELF_MACHINE, 0, 0);
2522c9fade2Saurel32             entry = elf_entry;
2532c9fade2Saurel32         }
2542c9fade2Saurel32         /* XXX try again as binary */
255ceee6da6SHollis Blanchard         if (success < 0) {
2566f76b817SAlistair Francis             error_report("could not load kernel '%s'", kernel_filename);
2572c9fade2Saurel32             exit(1);
2582c9fade2Saurel32         }
2592c9fade2Saurel32     }
2602c9fade2Saurel32 
2612c9fade2Saurel32     /* Load initrd. */
2622c9fade2Saurel32     if (initrd_filename) {
263ceee6da6SHollis Blanchard         initrd_size = load_image_targphys(initrd_filename, RAMDISK_ADDR,
264a0258e4aSIgor Mammedov                                           machine->ram_size - RAMDISK_ADDR);
2652c9fade2Saurel32 
2662c9fade2Saurel32         if (initrd_size < 0) {
2676f76b817SAlistair Francis             error_report("could not load ram disk '%s' at %x",
268ceee6da6SHollis Blanchard                          initrd_filename, RAMDISK_ADDR);
2692c9fade2Saurel32             exit(1);
2702c9fade2Saurel32         }
2712c9fade2Saurel32     }
2722c9fade2Saurel32 
2732c9fade2Saurel32     /* If we're loading a kernel directly, we must load the device tree too. */
2742c9fade2Saurel32     if (kernel_filename) {
2758d42c851SDaniel Henrique Barboza         if (bamboo_load_device_tree(machine, FDT_ADDR,
2768d42c851SDaniel Henrique Barboza                                     RAMDISK_ADDR, initrd_size) < 0) {
2776f76b817SAlistair Francis             error_report("couldn't load device tree");
2782c9fade2Saurel32             exit(1);
2792c9fade2Saurel32         }
2802c9fade2Saurel32     }
2812c9fade2Saurel32 }
2822c9fade2Saurel32 
283e264d29dSEduardo Habkost static void bamboo_machine_init(MachineClass *mc)
284f80f9ec9SAnthony Liguori {
285e264d29dSEduardo Habkost     mc->desc = "bamboo";
286e264d29dSEduardo Habkost     mc->init = bamboo_init;
287376d7a2aSIgor Mammedov     mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("440epb");
288b28f0188SIgor Mammedov     mc->default_ram_id = "ppc4xx.sdram";
289053b7086SThomas Huth     mc->default_nic = "e1000";
290f80f9ec9SAnthony Liguori }
291f80f9ec9SAnthony Liguori 
292e264d29dSEduardo Habkost DEFINE_MACHINE("bamboo", bamboo_machine_init)
293