xref: /qemu/hw/ppc/ppc440_bamboo.c (revision 06b40d250ecfa1633209c2e431a7a38acfd03a98)
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"
1874781c08SPhilippe Mathieu-Daudé #include "exec/page-protection.h"
191422e32dSPaolo Bonzini #include "net/net.h"
2083c9f4caSPaolo Bonzini #include "hw/pci/pci.h"
2183c9f4caSPaolo Bonzini #include "hw/boards.h"
2232cad1ffSPhilippe Mathieu-Daudé #include "system/kvm.h"
2332cad1ffSPhilippe Mathieu-Daudé #include "system/device_tree.h"
2483c9f4caSPaolo Bonzini #include "hw/loader.h"
25ca20cf32SBlue Swirl #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"
2932cad1ffSPhilippe Mathieu-Daudé #include "system/system.h"
3032cad1ffSPhilippe Mathieu-Daudé #include "system/reset.h"
3183c9f4caSPaolo 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"
352c9fade2Saurel32 
368d42c851SDaniel Henrique Barboza #include <libfdt.h>
378d42c851SDaniel Henrique Barboza 
382c9fade2Saurel32 #define BINARY_DEVICE_TREE_FILE "bamboo.dtb"
392c9fade2Saurel32 
40ceee6da6SHollis Blanchard /* from u-boot */
41ceee6da6SHollis Blanchard #define KERNEL_ADDR  0x1000000
42ceee6da6SHollis Blanchard #define FDT_ADDR     0x1800000
43ceee6da6SHollis Blanchard #define RAMDISK_ADDR 0x1900000
44ceee6da6SHollis Blanchard 
453960b04dSAlexander Graf #define PPC440EP_PCI_CONFIG     0xeec00000
463960b04dSAlexander Graf #define PPC440EP_PCI_INTACK     0xeed00000
473960b04dSAlexander Graf #define PPC440EP_PCI_SPECIAL    0xeed00000
483960b04dSAlexander Graf #define PPC440EP_PCI_REGS       0xef400000
493960b04dSAlexander Graf #define PPC440EP_PCI_IO         0xe8000000
503960b04dSAlexander Graf #define PPC440EP_PCI_IOLEN      0x00010000
513960b04dSAlexander Graf 
52a8170e5eSAvi Kivity static hwaddr entry;
53b10a04b5SAlexander Graf 
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,
56a8170e5eSAvi Kivity                                    hwaddr initrd_base,
578d42c851SDaniel Henrique Barboza                                    hwaddr initrd_size)
582c9fade2Saurel32 {
59dbf916d8SAurelien Jarno     int ret = -1;
608d42c851SDaniel Henrique Barboza     uint32_t mem_reg_property[] = { 0, 0, cpu_to_be32(machine->ram_size) };
615cea8590SPaul Brook     char *filename;
627ec632b4Spbrook     int fdt_size;
63dbf916d8SAurelien Jarno     void *fdt;
647dadd40cSAlexander Graf     uint32_t tb_freq = 400000000;
657dadd40cSAlexander Graf     uint32_t clock_freq = 400000000;
662c9fade2Saurel32 
67*fcb1ad45SBALATON Zoltan     filename = qemu_find_file(QEMU_FILE_TYPE_DTB, BINARY_DEVICE_TREE_FILE);
685cea8590SPaul Brook     if (!filename) {
69400431efSDaniel Henrique Barboza         return -1;
705cea8590SPaul Brook     }
715cea8590SPaul Brook     fdt = load_device_tree(filename, &fdt_size);
727267c094SAnthony Liguori     g_free(filename);
735cea8590SPaul Brook     if (fdt == NULL) {
74400431efSDaniel Henrique Barboza         return -1;
755cea8590SPaul Brook     }
762c9fade2Saurel32 
772c9fade2Saurel32     /* Manipulate device tree in memory. */
782c9fade2Saurel32 
795a4348d1SPeter Crosthwaite     ret = qemu_fdt_setprop(fdt, "/memory", "reg", mem_reg_property,
802c9fade2Saurel32                            sizeof(mem_reg_property));
8195e22932SBALATON Zoltan     if (ret < 0) {
822c9fade2Saurel32         fprintf(stderr, "couldn't set /memory/reg\n");
8395e22932SBALATON Zoltan     }
845a4348d1SPeter Crosthwaite     ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start",
852c9fade2Saurel32                                 initrd_base);
8695e22932SBALATON Zoltan     if (ret < 0) {
872c9fade2Saurel32         fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
8895e22932SBALATON Zoltan     }
895a4348d1SPeter Crosthwaite     ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
902c9fade2Saurel32                                 (initrd_base + initrd_size));
9195e22932SBALATON Zoltan     if (ret < 0) {
922c9fade2Saurel32         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) {
972c9fade2Saurel32         fprintf(stderr, "couldn't set /chosen/bootargs\n");
9895e22932SBALATON Zoltan     }
992c9fade2Saurel32 
1005a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/cpus/cpu@0", "clock-frequency",
1017dadd40cSAlexander Graf                           clock_freq);
1025a4348d1SPeter Crosthwaite     qemu_fdt_setprop_cell(fdt, "/cpus/cpu@0", "timebase-frequency",
1037dadd40cSAlexander Graf                           tb_freq);
1042c9fade2Saurel32 
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;
1112c9fade2Saurel32 }
1122c9fade2Saurel32 
main_cpu_reset(void * opaque)113b10a04b5SAlexander Graf static void main_cpu_reset(void *opaque)
114b10a04b5SAlexander Graf {
115182fbbf2SAndreas Färber     PowerPCCPU *cpu = opaque;
116182fbbf2SAndreas Färber     CPUPPCState *env = &cpu->env;
117b10a04b5SAlexander Graf 
118182fbbf2SAndreas Färber     cpu_reset(CPU(cpu));
119ab3dd749SPhilippe Mathieu-Daudé     env->gpr[1] = (16 * MiB) - 8;
120b10a04b5SAlexander Graf     env->gpr[3] = FDT_ADDR;
121b10a04b5SAlexander Graf     env->nip = entry;
12272718e9aSAlexander Graf 
123afff8800SBALATON Zoltan     /* Create a mapping spanning the 32bit addr space. */
124afff8800SBALATON Zoltan     booke_set_tlb(&env->tlb.tlbe[0], 0, 0, 1U << 31);
125afff8800SBALATON Zoltan     booke_set_tlb(&env->tlb.tlbe[1], 0x80000000, 0x80000000, 1U << 31);
126b10a04b5SAlexander Graf }
127b10a04b5SAlexander Graf 
bamboo_init(MachineState * machine)1283ef96221SMarcel Apfelbaum static void bamboo_init(MachineState *machine)
1292c9fade2Saurel32 {
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);
1332c9fade2Saurel32     unsigned int pci_irq_nrs[4] = { 28, 27, 26, 25 };
1343e9f0113SRichard Henderson     MemoryRegion *address_space_mem = get_system_memory();
13568501502SPaolo Bonzini     MemoryRegion *isa = g_new(MemoryRegion, 1);
1362c9fade2Saurel32     PCIBus *pcibus;
137322164e0SAndreas Färber     PowerPCCPU *cpu;
138e2684c0bSAndreas Färber     CPUPPCState *env;
1392c9fade2Saurel32     target_long initrd_size = 0;
14034ba1dc8SAlexander Graf     DeviceState *dev;
1410270d74eSPeter Maydell     DeviceState *uicdev;
1420270d74eSPeter Maydell     SysBusDevice *uicsbd;
143ceee6da6SHollis Blanchard     int success;
1442c9fade2Saurel32 
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));
152322164e0SAndreas Färber     env = &cpu->env;
15334ba1dc8SAlexander Graf 
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 
160182fbbf2SAndreas Färber     qemu_register_reset(main_cpu_reset, cpu);
161a34a92b9SAndreas Färber     ppc_booke_timers_init(cpu, 400000000, 0);
16234ba1dc8SAlexander Graf     ppc_dcr_init(env, NULL, NULL);
16334ba1dc8SAlexander Graf 
16434ba1dc8SAlexander Graf     /* 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));
17334ba1dc8SAlexander Graf 
17434ba1dc8SAlexander Graf     /* 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));
18034ba1dc8SAlexander Graf     /* 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));
18434ba1dc8SAlexander Graf 
18534ba1dc8SAlexander Graf     /* 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]),
19134ba1dc8SAlexander Graf                                 NULL);
19234ba1dc8SAlexander Graf     pcibus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
19334ba1dc8SAlexander Graf     if (!pcibus) {
1946f76b817SAlistair Francis         error_report("couldn't create PCI controller");
19534ba1dc8SAlexander Graf         exit(1);
19634ba1dc8SAlexander Graf     }
19734ba1dc8SAlexander Graf 
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);
20134ba1dc8SAlexander Graf 
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),
20634ba1dc8SAlexander Graf                        DEVICE_BIG_ENDIAN);
20734ba1dc8SAlexander Graf     }
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),
21234ba1dc8SAlexander Graf                        DEVICE_BIG_ENDIAN);
21334ba1dc8SAlexander Graf     }
2142c9fade2Saurel32 
2152c9fade2Saurel32     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);
2212c9fade2Saurel32     }
2222c9fade2Saurel32 
2232c9fade2Saurel32     /* Load kernel. */
2242c9fade2Saurel32     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);
228ceee6da6SHollis Blanchard         if (success < 0) {
229617160c9SBALATON Zoltan             uint64_t elf_entry;
2304366e1dbSLiam Merwick             success = load_elf(kernel_filename, NULL, NULL, NULL, &elf_entry,
231adc1a4a2SPhilippe Mathieu-Daudé                                NULL, NULL, NULL,
232adc1a4a2SPhilippe Mathieu-Daudé                                ELFDATA2MSB, PPC_ELF_MACHINE, 0, 0);
2332c9fade2Saurel32             entry = elf_entry;
2342c9fade2Saurel32         }
2352c9fade2Saurel32         /* XXX try again as binary */
236ceee6da6SHollis Blanchard         if (success < 0) {
2376f76b817SAlistair Francis             error_report("could not load kernel '%s'", kernel_filename);
2382c9fade2Saurel32             exit(1);
2392c9fade2Saurel32         }
2402c9fade2Saurel32     }
2412c9fade2Saurel32 
2422c9fade2Saurel32     /* Load initrd. */
2432c9fade2Saurel32     if (initrd_filename) {
244ceee6da6SHollis Blanchard         initrd_size = load_image_targphys(initrd_filename, RAMDISK_ADDR,
245a0258e4aSIgor Mammedov                                           machine->ram_size - RAMDISK_ADDR);
2462c9fade2Saurel32 
2472c9fade2Saurel32         if (initrd_size < 0) {
2486f76b817SAlistair Francis             error_report("could not load ram disk '%s' at %x",
249ceee6da6SHollis Blanchard                          initrd_filename, RAMDISK_ADDR);
2502c9fade2Saurel32             exit(1);
2512c9fade2Saurel32         }
2522c9fade2Saurel32     }
2532c9fade2Saurel32 
2542c9fade2Saurel32     /* If we're loading a kernel directly, we must load the device tree too. */
2552c9fade2Saurel32     if (kernel_filename) {
2568d42c851SDaniel Henrique Barboza         if (bamboo_load_device_tree(machine, FDT_ADDR,
2578d42c851SDaniel Henrique Barboza                                     RAMDISK_ADDR, initrd_size) < 0) {
2586f76b817SAlistair Francis             error_report("couldn't load device tree");
2592c9fade2Saurel32             exit(1);
2602c9fade2Saurel32         }
2612c9fade2Saurel32     }
2622c9fade2Saurel32 }
2632c9fade2Saurel32 
bamboo_machine_init(MachineClass * mc)264e264d29dSEduardo Habkost static void bamboo_machine_init(MachineClass *mc)
265f80f9ec9SAnthony Liguori {
266e264d29dSEduardo Habkost     mc->desc = "bamboo";
267e264d29dSEduardo Habkost     mc->init = bamboo_init;
268376d7a2aSIgor Mammedov     mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("440epb");
269b28f0188SIgor Mammedov     mc->default_ram_id = "ppc4xx.sdram";
270053b7086SThomas Huth     mc->default_nic = "e1000";
271f80f9ec9SAnthony Liguori }
272f80f9ec9SAnthony Liguori 
273e264d29dSEduardo Habkost DEFINE_MACHINE("bamboo", bamboo_machine_init)
274