diff --git a/Makefile b/Makefile index 01f012198b..85523d775e 100644 --- a/Makefile +++ b/Makefile @@ -222,7 +222,7 @@ common de-ch es fo fr-ca hu ja mk nl-be pt sl tr ifdef INSTALL_BLOBS BLOBS=bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \ video.x openbios-sparc32 openbios-sparc64 pxe-ne2k_pci.bin \ -pxe-rtl8139.bin pxe-pcnet.bin pxe-e1000.bin +pxe-rtl8139.bin pxe-pcnet.bin pxe-e1000.bin bamboo.dtb else BLOBS= endif diff --git a/Makefile.target b/Makefile.target index ef2d25f7c8..c4d0f05c26 100644 --- a/Makefile.target +++ b/Makefile.target @@ -655,7 +655,7 @@ OBJS+= heathrow_pic.o grackle_pci.o ppc_oldworld.o OBJS+= unin_pci.o ppc_chrp.o # PowerPC 4xx boards OBJS+= pflash_cfi02.o ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o -OBJS+= ppc440.o +OBJS+= ppc440.o ppc440_bamboo.o ifdef FDT_LIBS OBJS+= device_tree.o LIBS+= $(FDT_LIBS) diff --git a/hw/boards.h b/hw/boards.h index a7b8126bbd..bff1cf06c6 100644 --- a/hw/boards.h +++ b/hw/boards.h @@ -38,6 +38,7 @@ extern QEMUMachine core99_machine; extern QEMUMachine heathrow_machine; extern QEMUMachine ref405ep_machine; extern QEMUMachine taihu_machine; +extern QEMUMachine bamboo_machine; /* mips_r4k.c */ extern QEMUMachine mips_machine; diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c new file mode 100644 index 0000000000..a6fc75823c --- /dev/null +++ b/hw/ppc440_bamboo.c @@ -0,0 +1,190 @@ +/* + * Qemu PowerPC 440 Bamboo board emulation + * + * Copyright 2007 IBM Corporation. + * Authors: + * Jerone Young + * Christian Ehrhardt + * Hollis Blanchard + * + * This work is licensed under the GNU GPL license version 2 or later. + * + */ + +#include "config.h" +#include "qemu-common.h" +#include "net.h" +#include "hw.h" +#include "pci.h" +#include "virtio-blk.h" +#include "boards.h" +#include "sysemu.h" +#include "ppc440.h" +#include "kvm.h" +#include "kvm_ppc.h" +#include "device_tree.h" + +#define BINARY_DEVICE_TREE_FILE "bamboo.dtb" + +static void *bamboo_load_device_tree(void *addr, + uint32_t ramsize, + target_phys_addr_t initrd_base, + target_phys_addr_t initrd_size, + const char *kernel_cmdline) +{ + void *fdt = NULL; +#ifdef HAVE_FDT + uint32_t mem_reg_property[] = { 0, 0, ramsize }; + char *path; + int pathlen; + int ret; + + pathlen = snprintf(NULL, 0, "%s/%s", bios_dir, BINARY_DEVICE_TREE_FILE) + 1; + path = qemu_malloc(pathlen); + if (path == NULL) + return NULL; + + snprintf(path, pathlen, "%s/%s", bios_dir, BINARY_DEVICE_TREE_FILE); + + fdt = load_device_tree(path, addr); + free(path); + if (fdt == NULL) + goto out; + + /* Manipulate device tree in memory. */ + + ret = qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property, + sizeof(mem_reg_property)); + if (ret < 0) + fprintf(stderr, "couldn't set /memory/reg\n"); + + ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start", + initrd_base); + if (ret < 0) + fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n"); + + ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end", + (initrd_base + initrd_size)); + if (ret < 0) + fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n"); + + ret = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", + kernel_cmdline); + if (ret < 0) + fprintf(stderr, "couldn't set /chosen/bootargs\n"); + + if (kvm_enabled()) + kvmppc_fdt_update(fdt); + +out: +#endif + + return fdt; +} + +static void bamboo_init(ram_addr_t ram_size, int vga_ram_size, + const char *boot_device, DisplayState *ds, + const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename, + const char *cpu_model) +{ + unsigned int pci_irq_nrs[4] = { 28, 27, 26, 25 }; + NICInfo *nd; + PCIBus *pcibus; + CPUState *env; + uint64_t elf_entry; + uint64_t elf_lowaddr; + target_ulong entry = 0; + target_ulong loadaddr = 0; + target_long kernel_size = 0; + target_ulong initrd_base = 0; + target_long initrd_size = 0; + target_ulong dt_base = 0; + void *fdt; + int i; + + /* Setup CPU. */ + env = ppc440ep_init(&ram_size, &pcibus, pci_irq_nrs, 1); + + if (pcibus) { + int unit_id = 0; + + /* Add virtio block devices. */ + while ((i = drive_get_index(IF_VIRTIO, 0, unit_id)) != -1) { + virtio_blk_init(pcibus, drives_table[i].bdrv); + unit_id++; + } + + /* Register network interfaces. */ + for (i = 0; i < nb_nics; i++) { + nd = &nd_table[i]; + if (!nd->model) { + /* There are no PCI NICs on the Bamboo board, but there are + * PCI slots, so we can pick model whatever we want. */ + nd->model = "e1000"; + } + pci_nic_init(pcibus, nd, -1); + } + } + + /* Load kernel. */ + if (kernel_filename) { + kernel_size = load_uimage(kernel_filename, &entry, &loadaddr, NULL); + if (kernel_size < 0) { + kernel_size = load_elf(kernel_filename, 0, &elf_entry, &elf_lowaddr, + NULL); + entry = elf_entry; + loadaddr = elf_lowaddr; + } + /* XXX try again as binary */ + if (kernel_size < 0) { + fprintf(stderr, "qemu: could not load kernel '%s'\n", + kernel_filename); + exit(1); + } + } + + /* Load initrd. */ + if (initrd_filename) { + initrd_base = kernel_size + loadaddr; + initrd_size = load_image(initrd_filename, phys_ram_base + initrd_base); + + if (initrd_size < 0) { + fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", + initrd_filename); + exit(1); + } + } + + /* If we're loading a kernel directly, we must load the device tree too. */ + if (kernel_filename) { + if (initrd_base) + dt_base = initrd_base + initrd_size; + else + dt_base = kernel_size + loadaddr; + + fdt = bamboo_load_device_tree(phys_ram_base + dt_base, ram_size, + initrd_base, initrd_size, kernel_cmdline); + if (fdt == NULL) { + fprintf(stderr, "couldn't load device tree\n"); + exit(1); + } + + /* Set initial guest state. */ + env->gpr[1] = (16<<20) - 8; + env->gpr[3] = dt_base; + env->nip = entry; + /* XXX we currently depend on KVM to create some initial TLB entries. */ + } + + if (kvm_enabled()) + kvmppc_init(); +} + +QEMUMachine bamboo_machine = { + .name = "bamboo", + .desc = "bamboo", + .init = bamboo_init, + .ram_require = 8<<20 | RAMSIZE_FIXED, +}; diff --git a/pc-bios/bamboo.dts b/pc-bios/bamboo.dts new file mode 100644 index 0000000000..655442ca69 --- /dev/null +++ b/pc-bios/bamboo.dts @@ -0,0 +1,234 @@ +/* + * Device Tree Source for AMCC Bamboo + * + * Copyright (c) 2006, 2007 IBM Corp. + * Josh Boyer + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without + * any warranty of any kind, whether express or implied. + */ + +/ { + #address-cells = <2>; + #size-cells = <1>; + model = "amcc,bamboo"; + compatible = "amcc,bamboo"; + dcr-parent = <&/cpus/cpu@0>; + + aliases { + serial0 = &UART0; + serial1 = &UART1; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + model = "PowerPC,440EP"; + reg = <0>; + clock-frequency = <1fca0550>; + timebase-frequency = <017d7840>; + i-cache-line-size = <20>; + d-cache-line-size = <20>; + i-cache-size = <8000>; + d-cache-size = <8000>; + dcr-controller; + dcr-access-method = "native"; + }; + }; + + memory { + device_type = "memory"; + reg = <0 0 9000000>; + }; + + UIC0: interrupt-controller0 { + compatible = "ibm,uic-440ep","ibm,uic"; + interrupt-controller; + cell-index = <0>; + dcr-reg = <0c0 009>; + #address-cells = <0>; + #size-cells = <0>; + #interrupt-cells = <2>; + }; +/* + UIC1: interrupt-controller1 { + compatible = "ibm,uic-440ep","ibm,uic"; + interrupt-controller; + cell-index = <1>; + dcr-reg = <0d0 009>; + #address-cells = <0>; + #size-cells = <0>; + #interrupt-cells = <2>; + interrupts = <1e 4 1f 4>; + interrupt-parent = <&UIC0>; + }; +*/ + + SDR0: sdr { + compatible = "ibm,sdr-440ep"; + dcr-reg = <00e 002>; + }; + + CPR0: cpr { + compatible = "ibm,cpr-440ep"; + dcr-reg = <00c 002>; + }; + + plb { + compatible = "ibm,plb-440ep", "ibm,plb-440gp", "ibm,plb4"; + #address-cells = <2>; + #size-cells = <1>; + ranges; + clock-frequency = <07f28154>; + + SDRAM0: sdram { + compatible = "ibm,sdram-440ep", "ibm,sdram-405gp"; + dcr-reg = <010 2>; + }; + + DMA0: dma { + compatible = "ibm,dma-440ep", "ibm,dma-440gp"; + dcr-reg = <100 027>; + }; + + POB0: opb { + compatible = "ibm,opb-440ep", "ibm,opb-440gp", "ibm,opb"; + #address-cells = <1>; + #size-cells = <1>; + /* Bamboo is oddball in the 44x world and doesn't use the ERPN + * bits. + */ + ranges = <00000000 0 00000000 80000000 + 80000000 0 80000000 80000000>; + /* interrupt-parent = <&UIC1>; */ + interrupts = <7 4>; + clock-frequency = <03f940aa>; + + EBC0: ebc { + compatible = "ibm,ebc-440ep", "ibm,ebc-440gp", "ibm,ebc"; + dcr-reg = <012 2>; + #address-cells = <2>; + #size-cells = <1>; + clock-frequency = <03f940aa>; + interrupts = <5 1>; + /* interrupt-parent = <&UIC1>; */ + }; + + UART0: serial@ef600300 { + device_type = "serial"; + compatible = "ns16550"; + reg = ; + virtual-reg = ; + clock-frequency = <00a8c000>; + current-speed = <1c200>; + interrupt-parent = <&UIC0>; + interrupts = <0 4>; + }; + + UART1: serial@ef600400 { + device_type = "serial"; + compatible = "ns16550"; + reg = ; + virtual-reg = ; + clock-frequency = <00a8c000>; + current-speed = <0>; + interrupt-parent = <&UIC0>; + interrupts = <1 4>; + }; +/* + UART2: serial@ef600500 { + device_type = "serial"; + compatible = "ns16550"; + reg = ; + virtual-reg = ; + clock-frequency = <0>; + current-speed = <0>; + interrupt-parent = <&UIC0>; + interrupts = <3 4>; + }; + + UART3: serial@ef600600 { + device_type = "serial"; + compatible = "ns16550"; + reg = ; + virtual-reg = ; + clock-frequency = <0>; + current-speed = <0>; + interrupt-parent = <&UIC0>; + interrupts = <4 4>; + }; + +*/ + IIC0: i2c@ef600700 { + device_type = "i2c"; + compatible = "ibm,iic-440ep", "ibm,iic-440gp", "ibm,iic"; + reg = ; + interrupt-parent = <&UIC0>; + interrupts = <2 4>; + }; + + IIC1: i2c@ef600800 { + device_type = "i2c"; + compatible = "ibm,iic-440ep", "ibm,iic-440gp", "ibm,iic"; + reg = ; + interrupt-parent = <&UIC0>; + interrupts = <7 4>; + }; + + ZMII0: emac-zmii@ef600d00 { + device_type = "zmii-interface"; + compatible = "ibm,zmii-440ep", "ibm,zmii-440gp", "ibm,zmii"; + reg = ; + }; + + }; + + PCI0: pci@ec000000 { + device_type = "pci"; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + compatible = "ibm,plb440ep-pci", "ibm,plb-pci"; + primary; + reg = <0 eec00000 8 /* Config space access */ + 0 eed00000 4 /* IACK */ + 0 eed00000 4 /* Special cycle */ + 0 ef400000 40>; /* Internal registers */ + + /* Outbound ranges, one memory and one IO, + * later cannot be changed. Chip supports a second + * IO range but we don't use it for now + */ + ranges = <02000000 0 a0000000 0 a0000000 0 20000000 + 01000000 0 00000000 0 e8000000 0 00010000>; + + /* Inbound 2GB range starting at 0 */ + dma-ranges = <42000000 0 0 0 0 0 80000000>; + + /* Bamboo has all 4 IRQ pins tied together per slot */ + interrupt-map-mask = ; + interrupt-map = < + /* IDSEL 1 */ + 0800 0 0 0 &UIC0 1c 8 + + /* IDSEL 2 */ + 1000 0 0 0 &UIC0 1b 8 + + /* IDSEL 3 */ + 1800 0 0 0 &UIC0 1a 8 + + /* IDSEL 4 */ + 2000 0 0 0 &UIC0 19 8 + >; + }; + + }; + + chosen { + linux,stdout-path = "/plb/opb/serial@ef600300"; + }; +}; diff --git a/target-ppc/machine.c b/target-ppc/machine.c index be0cbe1c26..ea2257b1c2 100644 --- a/target-ppc/machine.c +++ b/target-ppc/machine.c @@ -8,6 +8,7 @@ void register_machines(void) qemu_register_machine(&prep_machine); qemu_register_machine(&ref405ep_machine); qemu_register_machine(&taihu_machine); + qemu_register_machine(&bamboo_machine); } void cpu_save(QEMUFile *f, void *opaque)