xref: /openbmc/qemu/hw/ppc/ppc440_bamboo.c (revision 6b829602e2f10f301ff8508f3a6850a0e913142c)
153018216SPaolo Bonzini /*
253018216SPaolo Bonzini  * QEMU PowerPC 440 Bamboo board emulation
353018216SPaolo Bonzini  *
453018216SPaolo Bonzini  * Copyright 2007 IBM Corporation.
553018216SPaolo Bonzini  * Authors:
653018216SPaolo Bonzini  *  Jerone Young <jyoung5@us.ibm.com>
753018216SPaolo Bonzini  *  Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
853018216SPaolo Bonzini  *  Hollis Blanchard <hollisb@us.ibm.com>
953018216SPaolo Bonzini  *
1053018216SPaolo Bonzini  * This work is licensed under the GNU GPL license version 2 or later.
1153018216SPaolo Bonzini  *
1253018216SPaolo Bonzini  */
1353018216SPaolo Bonzini 
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"
1874781c08SPhilippe Mathieu-Daudé #include "exec/page-protection.h"
1953018216SPaolo Bonzini #include "net/net.h"
2053018216SPaolo Bonzini #include "hw/pci/pci.h"
2153018216SPaolo Bonzini #include "hw/boards.h"
2253018216SPaolo Bonzini #include "sysemu/kvm.h"
2353018216SPaolo Bonzini #include "sysemu/device_tree.h"
2453018216SPaolo Bonzini #include "hw/loader.h"
2553018216SPaolo Bonzini #include "elf.h"
267e6b5497SBernhard Beschow #include "hw/char/serial-mm.h"
270d09e41aSPaolo Bonzini #include "hw/ppc/ppc.h"
284d641f36SPhilippe Mathieu-Daudé #include "hw/pci-host/ppc4xx.h"
2953018216SPaolo Bonzini #include "sysemu/sysemu.h"
3071e8a915SMarkus Armbruster #include "sysemu/reset.h"
3153018216SPaolo Bonzini #include "hw/sysbus.h"
320270d74eSPeter Maydell #include "hw/intc/ppc-uic.h"
330270d74eSPeter Maydell #include "hw/qdev-properties.h"
340270d74eSPeter Maydell #include "qapi/error.h"
3553018216SPaolo Bonzini 
368d42c851SDaniel Henrique Barboza #include <libfdt.h>
378d42c851SDaniel Henrique Barboza 
3853018216SPaolo Bonzini #define BINARY_DEVICE_TREE_FILE "bamboo.dtb"
3953018216SPaolo Bonzini 
4053018216SPaolo Bonzini /* from u-boot */
4153018216SPaolo Bonzini #define KERNEL_ADDR  0x1000000
4253018216SPaolo Bonzini #define FDT_ADDR     0x1800000
4353018216SPaolo Bonzini #define RAMDISK_ADDR 0x1900000
4453018216SPaolo Bonzini 
4553018216SPaolo Bonzini #define PPC440EP_PCI_CONFIG     0xeec00000
4653018216SPaolo Bonzini #define PPC440EP_PCI_INTACK     0xeed00000
4753018216SPaolo Bonzini #define PPC440EP_PCI_SPECIAL    0xeed00000
4853018216SPaolo Bonzini #define PPC440EP_PCI_REGS       0xef400000
4953018216SPaolo Bonzini #define PPC440EP_PCI_IO         0xe8000000
5053018216SPaolo Bonzini #define PPC440EP_PCI_IOLEN      0x00010000
5153018216SPaolo Bonzini 
5253018216SPaolo Bonzini static hwaddr entry;
5353018216SPaolo Bonzini 
bamboo_load_device_tree(MachineState * machine,hwaddr addr,hwaddr initrd_base,hwaddr initrd_size)548d42c851SDaniel Henrique Barboza static int bamboo_load_device_tree(MachineState *machine,
558d42c851SDaniel Henrique Barboza                                    hwaddr addr,
5653018216SPaolo Bonzini                                    hwaddr initrd_base,
578d42c851SDaniel Henrique Barboza                                    hwaddr initrd_size)
5853018216SPaolo Bonzini {
5953018216SPaolo Bonzini     int ret = -1;
608d42c851SDaniel Henrique Barboza     uint32_t mem_reg_property[] = { 0, 0, cpu_to_be32(machine->ram_size) };
6153018216SPaolo Bonzini     char *filename;
6253018216SPaolo Bonzini     int fdt_size;
6353018216SPaolo Bonzini     void *fdt;
6453018216SPaolo Bonzini     uint32_t tb_freq = 400000000;
6553018216SPaolo Bonzini     uint32_t clock_freq = 400000000;
6653018216SPaolo Bonzini 
6753018216SPaolo Bonzini     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
6853018216SPaolo Bonzini     if (!filename) {
69400431efSDaniel Henrique Barboza         return -1;
7053018216SPaolo Bonzini     }
7153018216SPaolo Bonzini     fdt = load_device_tree(filename, &fdt_size);
7253018216SPaolo Bonzini     g_free(filename);
7353018216SPaolo Bonzini     if (fdt == NULL) {
74400431efSDaniel Henrique Barboza         return -1;
7553018216SPaolo Bonzini     }
7653018216SPaolo Bonzini 
7753018216SPaolo Bonzini     /* Manipulate device tree in memory. */
7853018216SPaolo Bonzini 
795a4348d1SPeter Crosthwaite     ret = qemu_fdt_setprop(fdt, "/memory", "reg", mem_reg_property,
8053018216SPaolo Bonzini                            sizeof(mem_reg_property));
8195e22932SBALATON Zoltan     if (ret < 0) {
8253018216SPaolo Bonzini         fprintf(stderr, "couldn't set /memory/reg\n");
8395e22932SBALATON Zoltan     }
845a4348d1SPeter Crosthwaite     ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start",
8553018216SPaolo Bonzini                                 initrd_base);
8695e22932SBALATON Zoltan     if (ret < 0) {
8753018216SPaolo Bonzini         fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
8895e22932SBALATON Zoltan     }
895a4348d1SPeter Crosthwaite     ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
9053018216SPaolo Bonzini                                 (initrd_base + initrd_size));
9195e22932SBALATON Zoltan     if (ret < 0) {
9253018216SPaolo Bonzini         fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
9395e22932SBALATON Zoltan     }
945a4348d1SPeter Crosthwaite     ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
958d42c851SDaniel Henrique Barboza                                   machine->kernel_cmdline);
9695e22932SBALATON Zoltan     if (ret < 0) {
9753018216SPaolo Bonzini         fprintf(stderr, "couldn't set /chosen/bootargs\n");
9895e22932SBALATON Zoltan     }
9953018216SPaolo Bonzini 
1005a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/cpus/cpu@0", "clock-frequency",
10153018216SPaolo Bonzini                           clock_freq);
1025a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/cpus/cpu@0", "timebase-frequency",
10353018216SPaolo Bonzini                           tb_freq);
10453018216SPaolo Bonzini 
105fe1479aaSMichael S. Tsirkin     rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
1068d42c851SDaniel Henrique Barboza 
1078d42c851SDaniel Henrique Barboza     /* Set ms->fdt for 'dumpdtb' QMP/HMP command */
1088d42c851SDaniel Henrique Barboza     machine->fdt = fdt;
1098d42c851SDaniel Henrique Barboza 
110fe1479aaSMichael S. Tsirkin     return 0;
11153018216SPaolo Bonzini }
11253018216SPaolo Bonzini 
main_cpu_reset(void * opaque)11353018216SPaolo Bonzini static void main_cpu_reset(void *opaque)
11453018216SPaolo Bonzini {
11553018216SPaolo Bonzini     PowerPCCPU *cpu = opaque;
11653018216SPaolo Bonzini     CPUPPCState *env = &cpu->env;
11753018216SPaolo Bonzini 
11853018216SPaolo Bonzini     cpu_reset(CPU(cpu));
119ab3dd749SPhilippe Mathieu-Daudé     env->gpr[1] = (16 * MiB) - 8;
12053018216SPaolo Bonzini     env->gpr[3] = FDT_ADDR;
12153018216SPaolo Bonzini     env->nip = entry;
12253018216SPaolo Bonzini 
123*afff8800SBALATON Zoltan     /* Create a mapping spanning the 32bit addr space. */
124*afff8800SBALATON Zoltan     booke_set_tlb(&env->tlb.tlbe[0], 0, 0, 1U << 31);
125*afff8800SBALATON Zoltan     booke_set_tlb(&env->tlb.tlbe[1], 0x80000000, 0x80000000, 1U << 31);
12653018216SPaolo Bonzini }
12753018216SPaolo Bonzini 
bamboo_init(MachineState * machine)1283ef96221SMarcel Apfelbaum static void bamboo_init(MachineState *machine)
12953018216SPaolo Bonzini {
1303ef96221SMarcel Apfelbaum     const char *kernel_filename = machine->kernel_filename;
1313ef96221SMarcel Apfelbaum     const char *initrd_filename = machine->initrd_filename;
132053b7086SThomas Huth     MachineClass *mc = MACHINE_GET_CLASS(machine);
13353018216SPaolo Bonzini     unsigned int pci_irq_nrs[4] = { 28, 27, 26, 25 };
13453018216SPaolo Bonzini     MemoryRegion *address_space_mem = get_system_memory();
13568501502SPaolo Bonzini     MemoryRegion *isa = g_new(MemoryRegion, 1);
13653018216SPaolo Bonzini     PCIBus *pcibus;
13753018216SPaolo Bonzini     PowerPCCPU *cpu;
13853018216SPaolo Bonzini     CPUPPCState *env;
13953018216SPaolo Bonzini     target_long initrd_size = 0;
14053018216SPaolo Bonzini     DeviceState *dev;
1410270d74eSPeter Maydell     DeviceState *uicdev;
1420270d74eSPeter Maydell     SysBusDevice *uicsbd;
14353018216SPaolo Bonzini     int success;
14453018216SPaolo Bonzini 
14574b2fd63SCédric Le Goater     if (kvm_enabled()) {
14674b2fd63SCédric Le Goater         error_report("machine %s does not support the KVM accelerator",
14774b2fd63SCédric Le Goater                      MACHINE_GET_CLASS(machine)->name);
14874b2fd63SCédric Le Goater         exit(EXIT_FAILURE);
14974b2fd63SCédric Le Goater     }
15074b2fd63SCédric Le Goater 
151376d7a2aSIgor Mammedov     cpu = POWERPC_CPU(cpu_create(machine->cpu_type));
15253018216SPaolo Bonzini     env = &cpu->env;
15353018216SPaolo Bonzini 
15400469dc3SValentin Plotkin     if (env->mmu_model != POWERPC_MMU_BOOKE) {
1556f76b817SAlistair Francis         error_report("MMU model %i not supported by this machine",
15600469dc3SValentin Plotkin                      env->mmu_model);
15700469dc3SValentin Plotkin         exit(1);
15800469dc3SValentin Plotkin     }
15900469dc3SValentin Plotkin 
16053018216SPaolo Bonzini     qemu_register_reset(main_cpu_reset, cpu);
16153018216SPaolo Bonzini     ppc_booke_timers_init(cpu, 400000000, 0);
16253018216SPaolo Bonzini     ppc_dcr_init(env, NULL, NULL);
16353018216SPaolo Bonzini 
16453018216SPaolo Bonzini     /* interrupt controller */
1650270d74eSPeter Maydell     uicdev = qdev_new(TYPE_PPC_UIC);
166a55b2136SBALATON Zoltan     ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(uicdev), cpu, &error_fatal);
167a55b2136SBALATON Zoltan     object_unref(OBJECT(uicdev));
1680270d74eSPeter Maydell     uicsbd = SYS_BUS_DEVICE(uicdev);
1690270d74eSPeter Maydell     sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_INT,
17047b60fc6SCédric Le Goater                        qdev_get_gpio_in(DEVICE(cpu), PPC40x_INPUT_INT));
1710270d74eSPeter Maydell     sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_CINT,
17247b60fc6SCédric Le Goater                        qdev_get_gpio_in(DEVICE(cpu), PPC40x_INPUT_CINT));
17353018216SPaolo Bonzini 
17453018216SPaolo Bonzini     /* SDRAM controller */
1754fc30e15SBALATON Zoltan     dev = qdev_new(TYPE_PPC4xx_SDRAM_DDR);
1764fc30e15SBALATON Zoltan     object_property_set_link(OBJECT(dev), "dram", OBJECT(machine->ram),
1774fc30e15SBALATON Zoltan                              &error_abort);
1784fc30e15SBALATON Zoltan     ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(dev), cpu, &error_fatal);
1794fc30e15SBALATON Zoltan     object_unref(OBJECT(dev));
18053018216SPaolo Bonzini     /* XXX 440EP's ECC interrupts are on UIC1, but we've only created UIC0. */
1814fc30e15SBALATON Zoltan     sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(uicdev, 14));
18268b9a2e3SBALATON Zoltan     /* Enable SDRAM memory regions, this should be done by the firmware */
1831e545fbcSBALATON Zoltan     ppc4xx_sdram_ddr_enable(PPC4xx_SDRAM_DDR(dev));
18453018216SPaolo Bonzini 
18553018216SPaolo Bonzini     /* PCI */
186e75a951bSBALATON Zoltan     dev = sysbus_create_varargs(TYPE_PPC4xx_PCI_HOST, PPC440EP_PCI_CONFIG,
1870270d74eSPeter Maydell                                 qdev_get_gpio_in(uicdev, pci_irq_nrs[0]),
1880270d74eSPeter Maydell                                 qdev_get_gpio_in(uicdev, pci_irq_nrs[1]),
1890270d74eSPeter Maydell                                 qdev_get_gpio_in(uicdev, pci_irq_nrs[2]),
1900270d74eSPeter Maydell                                 qdev_get_gpio_in(uicdev, pci_irq_nrs[3]),
19153018216SPaolo Bonzini                                 NULL);
19253018216SPaolo Bonzini     pcibus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
19353018216SPaolo Bonzini     if (!pcibus) {
1946f76b817SAlistair Francis         error_report("couldn't create PCI controller");
19553018216SPaolo Bonzini         exit(1);
19653018216SPaolo Bonzini     }
19753018216SPaolo Bonzini 
19868501502SPaolo Bonzini     memory_region_init_alias(isa, NULL, "isa_mmio",
19968501502SPaolo Bonzini                              get_system_io(), 0, PPC440EP_PCI_IOLEN);
20068501502SPaolo Bonzini     memory_region_add_subregion(get_system_memory(), PPC440EP_PCI_IO, isa);
20153018216SPaolo Bonzini 
2029bca0edbSPeter Maydell     if (serial_hd(0) != NULL) {
2030270d74eSPeter Maydell         serial_mm_init(address_space_mem, 0xef600300, 0,
2040270d74eSPeter Maydell                        qdev_get_gpio_in(uicdev, 0),
2059bca0edbSPeter Maydell                        PPC_SERIAL_MM_BAUDBASE, serial_hd(0),
20653018216SPaolo Bonzini                        DEVICE_BIG_ENDIAN);
20753018216SPaolo Bonzini     }
2089bca0edbSPeter Maydell     if (serial_hd(1) != NULL) {
2090270d74eSPeter Maydell         serial_mm_init(address_space_mem, 0xef600400, 0,
2100270d74eSPeter Maydell                        qdev_get_gpio_in(uicdev, 1),
2119bca0edbSPeter Maydell                        PPC_SERIAL_MM_BAUDBASE, serial_hd(1),
21253018216SPaolo Bonzini                        DEVICE_BIG_ENDIAN);
21353018216SPaolo Bonzini     }
21453018216SPaolo Bonzini 
21553018216SPaolo Bonzini     if (pcibus) {
21695e22932SBALATON Zoltan         /*
21795e22932SBALATON Zoltan          * There are no PCI NICs on the Bamboo board, but there are
21895e22932SBALATON Zoltan          * PCI slots, so we can pick whatever default model we want.
21995e22932SBALATON Zoltan          */
22036b6968dSDavid Woodhouse         pci_init_nic_devices(pcibus, mc->default_nic);
22153018216SPaolo Bonzini     }
22253018216SPaolo Bonzini 
22353018216SPaolo Bonzini     /* Load kernel. */
22453018216SPaolo Bonzini     if (kernel_filename) {
225617160c9SBALATON Zoltan         hwaddr loadaddr = LOAD_UIMAGE_LOADADDR_INVALID;
22625bda50aSMax Filippov         success = load_uimage(kernel_filename, &entry, &loadaddr, NULL,
22725bda50aSMax Filippov                               NULL, NULL);
22853018216SPaolo Bonzini         if (success < 0) {
229617160c9SBALATON Zoltan             uint64_t elf_entry;
2304366e1dbSLiam Merwick             success = load_elf(kernel_filename, NULL, NULL, NULL, &elf_entry,
231617160c9SBALATON Zoltan                                NULL, NULL, NULL, 1, PPC_ELF_MACHINE, 0, 0);
23253018216SPaolo Bonzini             entry = elf_entry;
23353018216SPaolo Bonzini         }
23453018216SPaolo Bonzini         /* XXX try again as binary */
23553018216SPaolo Bonzini         if (success < 0) {
2366f76b817SAlistair Francis             error_report("could not load kernel '%s'", kernel_filename);
23753018216SPaolo Bonzini             exit(1);
23853018216SPaolo Bonzini         }
23953018216SPaolo Bonzini     }
24053018216SPaolo Bonzini 
24153018216SPaolo Bonzini     /* Load initrd. */
24253018216SPaolo Bonzini     if (initrd_filename) {
24353018216SPaolo Bonzini         initrd_size = load_image_targphys(initrd_filename, RAMDISK_ADDR,
244a0258e4aSIgor Mammedov                                           machine->ram_size - RAMDISK_ADDR);
24553018216SPaolo Bonzini 
24653018216SPaolo Bonzini         if (initrd_size < 0) {
2476f76b817SAlistair Francis             error_report("could not load ram disk '%s' at %x",
24853018216SPaolo Bonzini                          initrd_filename, RAMDISK_ADDR);
24953018216SPaolo Bonzini             exit(1);
25053018216SPaolo Bonzini         }
25153018216SPaolo Bonzini     }
25253018216SPaolo Bonzini 
25353018216SPaolo Bonzini     /* If we're loading a kernel directly, we must load the device tree too. */
25453018216SPaolo Bonzini     if (kernel_filename) {
2558d42c851SDaniel Henrique Barboza         if (bamboo_load_device_tree(machine, FDT_ADDR,
2568d42c851SDaniel Henrique Barboza                                     RAMDISK_ADDR, initrd_size) < 0) {
2576f76b817SAlistair Francis             error_report("couldn't load device tree");
25853018216SPaolo Bonzini             exit(1);
25953018216SPaolo Bonzini         }
26053018216SPaolo Bonzini     }
26153018216SPaolo Bonzini }
26253018216SPaolo Bonzini 
bamboo_machine_init(MachineClass * mc)263e264d29dSEduardo Habkost static void bamboo_machine_init(MachineClass *mc)
26453018216SPaolo Bonzini {
265e264d29dSEduardo Habkost     mc->desc = "bamboo";
266e264d29dSEduardo Habkost     mc->init = bamboo_init;
267376d7a2aSIgor Mammedov     mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("440epb");
268b28f0188SIgor Mammedov     mc->default_ram_id = "ppc4xx.sdram";
269053b7086SThomas Huth     mc->default_nic = "e1000";
27053018216SPaolo Bonzini }
27153018216SPaolo Bonzini 
272e264d29dSEduardo Habkost DEFINE_MACHINE("bamboo", bamboo_machine_init)
273