From patchwork Mon Jan 9 16:59:08 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Langsdorf X-Patchwork-Id: 135075 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [140.186.70.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id AE50AB6FBE for ; Tue, 10 Jan 2012 03:59:58 +1100 (EST) Received: from localhost ([::1]:54345 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RkIZR-0001cc-7a for incoming@patchwork.ozlabs.org; Mon, 09 Jan 2012 11:59:41 -0500 Received: from eggs.gnu.org ([140.186.70.92]:49233) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RkIZ6-0001HT-Se for qemu-devel@nongnu.org; Mon, 09 Jan 2012 11:59:25 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1RkIYz-0004ah-3N for qemu-devel@nongnu.org; Mon, 09 Jan 2012 11:59:20 -0500 Received: from smtp161.dfw.emailsrvr.com ([67.192.241.161]:60359) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RkIYy-0004aC-SH for qemu-devel@nongnu.org; Mon, 09 Jan 2012 11:59:13 -0500 Received: from localhost (localhost.localdomain [127.0.0.1]) by smtp6.relay.dfw1a.emailsrvr.com (SMTP Server) with ESMTP id 7804127061A; Mon, 9 Jan 2012 11:59:10 -0500 (EST) X-Virus-Scanned: OK Received: by smtp6.relay.dfw1a.emailsrvr.com (Authenticated sender: mark.langsdorf-AT-calxeda.com) with ESMTPSA id 3B86A270605; Mon, 9 Jan 2012 11:59:10 -0500 (EST) From: Mark Langsdorf To: qemu-devel@nongnu.org Date: Mon, 9 Jan 2012 10:59:08 -0600 Message-Id: <1326128349-3465-6-git-send-email-mark.langsdorf@calxeda.com> X-Mailer: git-send-email 1.7.5.4 In-Reply-To: <1326128349-3465-1-git-send-email-mark.langsdorf@calxeda.com> References: <1325793761-10249-1-git-send-email-mark.langsdorf@calxeda.com> <1326128349-3465-1-git-send-email-mark.langsdorf@calxeda.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 3) X-Received-From: 67.192.241.161 Cc: i.mitsyanko@gmail.com, peter.maydell@linaro.org, Rob Herring , afaerber@suse.de, Mark Langsdorf Subject: [Qemu-devel] [PATCH v2 5/6] arm: SoC model for Calxeda Highbank X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: Rob Herring Adds support for Calxeda's Highbank SoC. Signed-off-by: Rob Herring Signed-off-by: Mark Langsdorf --- Changes from v1 Restructed the loading of sysram.bin and made it more clearly optional Made the regs structure into a proper qdev/sysbus object Removed some unnecessary include files Clarified the GPL version Simplified the reset function Removed the automatic detection and resetting of ram_size. Image MUST be loaded with -m 4089 or it will crash Added a guard for xgmac creation Added a fuller description in the QEMUMachine .desc field Makefile.target | 1 + hw/highbank.c | 267 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 268 insertions(+), 0 deletions(-) create mode 100644 hw/highbank.c diff --git a/Makefile.target b/Makefile.target index 5780a5f..56ca94d 100644 --- a/Makefile.target +++ b/Makefile.target @@ -339,6 +339,7 @@ obj-arm-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o obj-arm-y += arm_l2x0.o obj-arm-y += arm_mptimer.o obj-arm-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o +obj-arm-y += highbank.o obj-arm-y += pl061.o obj-arm-y += xgmac.o obj-arm-y += arm-semi.o diff --git a/hw/highbank.c b/hw/highbank.c new file mode 100644 index 0000000..823c2aa --- /dev/null +++ b/hw/highbank.c @@ -0,0 +1,267 @@ +/* + * Calxeda Highbank SoC emulation + * + * Copyright (c) 2010-2012 Calxeda + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + */ + +#include "sysbus.h" +#include "arm-misc.h" +#include "primecell.h" +#include "devices.h" +#include "loader.h" +#include "net.h" +#include "sysemu.h" +#include "boards.h" +#include "sysbus.h" +#include "blockdev.h" +#include "exec-memory.h" + +#define SMP_BOOT_ADDR 0 +#define NIRQ_GIC 160 + +/* Board init. */ +static void highbank_cpu_reset(void *opaque) +{ + CPUState *env = opaque; + + env->cp15.c15_config_base_address = 0xfff10000; +} + +#define NUM_REGS 0x200 +static void hb_regs_write(void *opaque, target_phys_addr_t offset, + uint64_t value, unsigned size) +{ + uint32_t *regs = opaque; + + if (offset == 0xf00) { + if (value == 1 || value == 2) { + qemu_system_reset_request(); + } else if (value == 3) { + qemu_system_shutdown_request(); + } + } + + regs[offset/4] = value; +} + +static uint64_t hb_regs_read(void *opaque, target_phys_addr_t offset, + unsigned size) +{ + uint32_t *regs = opaque; + uint32_t value = regs[offset/4]; + + if ((offset == 0x100) || (offset == 0x108) || (offset == 0x10C)) { + value |= 0x30000000; + } + + return value; +} + +static const MemoryRegionOps hb_mem_ops = { + .read = hb_regs_read, + .write = hb_regs_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +typedef struct { + SysBusDevice busdev; + MemoryRegion *iomem; + uint32_t regs[NUM_REGS]; +} highbank_regs_state; + +static VMStateDescription vmstate_highbank_regs = { + .name = "highbank-regs", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, highbank_regs_state, NUM_REGS), + VMSTATE_END_OF_LIST(), + }, +}; + +static int highbank_regs_init(SysBusDevice *dev) +{ + highbank_regs_state *s = FROM_SYSBUS(highbank_regs_state, dev); + + s->iomem = g_new(MemoryRegion, 1); + s->regs[0x40] = 0x05F20121; + s->regs[0x41] = 0x2; + s->regs[0x42] = 0x05F30121; + s->regs[0x43] = 0x05F40121; + memory_region_init_io(s->iomem, &hb_mem_ops, s->regs, "highbank_regs", + 0x1000); + + return 0; +} + +static SysBusDeviceInfo highbank_regs_info = { + .init = highbank_regs_init, + .qdev.name = "highbank-regs", + .qdev.desc = "Calxeda Highbank registers", + .qdev.size = sizeof(highbank_regs_state), + .qdev.vmsd = &vmstate_highbank_regs, +}; + +static void highbank_regs_register_device(void) +{ + sysbus_register_withprop(&highbank_regs_info); +} + +device_init(highbank_regs_register_device) + +static struct arm_boot_info highbank_binfo; + +static void highbank_init(ram_addr_t ram_size, + const char *boot_device, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + CPUState *env = NULL; + DeviceState *dev; + SysBusDevice *busdev; + qemu_irq *irqp; + qemu_irq pic[128]; + int n; + qemu_irq cpu_irq[4]; + MemoryRegion *sysram; + MemoryRegion *dram; + MemoryRegion *sysmem; + char *sysboot_filename; + highbank_regs_state *s; + + if (!cpu_model) { + cpu_model = "cortex-a9"; + } + + for (n = 0; n < smp_cpus; n++) { + env = cpu_init(cpu_model); + if (!env) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } + irqp = arm_pic_init_cpu(env); + cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ]; + qemu_register_reset(highbank_cpu_reset, env); + } + + sysmem = get_system_memory(); + dram = g_new(MemoryRegion, 1); + memory_region_init_ram(dram, "highbank.dram", ram_size); + /* SDRAM at address zero. */ + memory_region_add_subregion(sysmem, 0, dram); + + sysram = g_new(MemoryRegion, 1); + memory_region_init_ram(sysram, "highbank.sysram", 0x8000); + memory_region_add_subregion(sysmem, 0xfff88000, sysram); + if (bios_name != NULL) { + sysboot_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); + if (sysboot_filename != NULL) { + uint32_t filesize = get_image_size(sysboot_filename); + if (load_image_targphys("sysram.bin", 0xfff88000, filesize) < 0) { + hw_error("Unable to load %s\n", bios_name); + } + } else { + hw_error("Unable to find %s\n", bios_name); + } + } + + dev = qdev_create(NULL, "a9mpcore_priv"); + qdev_prop_set_uint32(dev, "num-cpu", smp_cpus); + qdev_prop_set_uint32(dev, "num-irq", NIRQ_GIC); + qdev_init_nofail(dev); + busdev = sysbus_from_qdev(dev); + sysbus_mmio_map(busdev, 0, 0xfff10000); + for (n = 0; n < smp_cpus; n++) { + sysbus_connect_irq(busdev, n, cpu_irq[n]); + } + + for (n = 0; n < 128; n++) { + pic[n] = qdev_get_gpio_in(dev, n); + } + + dev = qdev_create(NULL, "l2x0"); + qdev_init_nofail(dev); + busdev = sysbus_from_qdev(dev); + sysbus_mmio_map(busdev, 0, 0xfff12000); + + dev = qdev_create(NULL, "sp804"); + qdev_prop_set_uint32(dev, "freq0", 150000000); + qdev_prop_set_uint32(dev, "freq1", 150000000); + qdev_init_nofail(dev); + busdev = sysbus_from_qdev(dev); + sysbus_mmio_map(busdev, 0, 0xfff34000); + sysbus_connect_irq(busdev, 0, pic[18]); + sysbus_create_simple("pl011", 0xfff36000, pic[20]); + + dev = qdev_create(NULL, "highbank-regs"); + qdev_init_nofail(dev); + busdev = sysbus_from_qdev(dev); + s = FROM_SYSBUS(highbank_regs_state, busdev); + memory_region_add_subregion(sysmem, 0xfff3c000, s->iomem); + + sysbus_create_simple("pl061", 0xfff30000, pic[14]); + sysbus_create_simple("pl061", 0xfff31000, pic[15]); + sysbus_create_simple("pl061", 0xfff32000, pic[16]); + sysbus_create_simple("pl061", 0xfff33000, pic[17]); + sysbus_create_simple("pl031", 0xfff35000, pic[19]); + sysbus_create_simple("pl022", 0xfff39000, pic[23]); + + sysbus_create_simple("sysbus-ahci", 0xffe08000, pic[83]); + + if (nd_table[0].vlan) { + qemu_check_nic_model(&nd_table[0], "xgmac"); + dev = qdev_create(NULL, "xgmac"); + qdev_set_nic_properties(dev, &nd_table[0]); + qdev_init_nofail(dev); + sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0xfff50000); + sysbus_connect_irq(sysbus_from_qdev(dev), 0, pic[77]); + sysbus_connect_irq(sysbus_from_qdev(dev), 1, pic[78]); + sysbus_connect_irq(sysbus_from_qdev(dev), 2, pic[79]); + + qemu_check_nic_model(&nd_table[1], "xgmac"); + dev = qdev_create(NULL, "xgmac"); + qdev_set_nic_properties(dev, &nd_table[1]); + qdev_init_nofail(dev); + sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0xfff51000); + sysbus_connect_irq(sysbus_from_qdev(dev), 0, pic[80]); + sysbus_connect_irq(sysbus_from_qdev(dev), 1, pic[81]); + sysbus_connect_irq(sysbus_from_qdev(dev), 2, pic[82]); + } + + highbank_binfo.ram_size = ram_size; + highbank_binfo.kernel_filename = kernel_filename; + highbank_binfo.kernel_cmdline = kernel_cmdline; + highbank_binfo.initrd_filename = initrd_filename; + highbank_binfo.board_id = -1; /* provided by deviceTree */ + arm_load_kernel(env, &highbank_binfo); +} + +static QEMUMachine highbank_machine = { + .name = "highbank", + .desc = "Calxeda Highbank (ECX-1000)", + .init = highbank_init, + .use_scsi = 1, + .max_cpus = 4, + .no_vga = 1, +}; + +static void highbank_machine_init(void) +{ + qemu_register_machine(&highbank_machine); +} + +machine_init(highbank_machine_init);