From patchwork Mon Sep 17 09:03:01 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Peter A. G. Crosthwaite" X-Patchwork-Id: 184356 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 5A1332C0083 for ; Mon, 17 Sep 2012 19:38:49 +1000 (EST) Received: from localhost ([::1]:33500 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TDXFx-000438-1c for incoming@patchwork.ozlabs.org; Mon, 17 Sep 2012 05:04:41 -0400 Received: from eggs.gnu.org ([208.118.235.92]:35819) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TDXFp-0003rD-60 for qemu-devel@nongnu.org; Mon, 17 Sep 2012 05:04:35 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1TDXFj-0001gq-UK for qemu-devel@nongnu.org; Mon, 17 Sep 2012 05:04:33 -0400 Received: from mail-ie0-f173.google.com ([209.85.223.173]:39068) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TDXFj-0001XC-Ny for qemu-devel@nongnu.org; Mon, 17 Sep 2012 05:04:27 -0400 Received: by mail-ie0-f173.google.com with SMTP id c10so8784577ieb.4 for ; Mon, 17 Sep 2012 02:04:27 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references :in-reply-to:references:x-gm-message-state; bh=z+iWSkpyHPOLqFrMlztx0tq4wLXL+43rK/k4CdqGaP4=; b=AkJ2fZWaReyy5/wLVzmwUN9nbZJctL8SjqmpVFYzlL1bmzT0QadLZw0YwDhzwtR/b2 AHPO88fnBbbxZfVqSFnYeG2YvhB08aRp9Nw74qjWNpQmi6IlT9/AeAnqDXe1QnHbBLmQ H8n9w5GPnX9jiSiq/WKaKbcsX50kFKzE/yvYyO51Lm9iw7K9wP6cLtkZIrdKJQAfbpDE n1iKvr6JDB/fxW2QbZTOrTy7T0t/h7LljuGAm4c+C0KHdDckz/hZ4z015PVYS9C1i4nh JKRKwCJLIjhQBqtGBkcENpFsBZ2dkybBWgygVDWrlXXoLYGclHM8u0qt0Iwmd7EC0i7J OdUw== Received: by 10.42.89.1 with SMTP id e1mr8248956icm.8.1347872667429; Mon, 17 Sep 2012 02:04:27 -0700 (PDT) Received: from localhost ([124.148.20.9]) by mx.google.com with ESMTPS id y9sm16573326igm.10.2012.09.17.02.04.24 (version=TLSv1/SSLv3 cipher=OTHER); Mon, 17 Sep 2012 02:04:26 -0700 (PDT) From: "Peter A. G. Crosthwaite" To: qemu-devel@nongnu.org, edgar.iglesias@gmail.com Date: Mon, 17 Sep 2012 19:03:01 +1000 Message-Id: <368cdf3dac244fdf87e77855df93b7eb9463dc70.1347871922.git.peter.crosthwaite@petalogix.com> X-Mailer: git-send-email 1.7.0.4 In-Reply-To: References: In-Reply-To: References: X-Gm-Message-State: ALoCoQniJU7U91EGkDsgljciGsQ44jfGUlKQynTph/JrmYT4LyBULbIzKpZGz63UUnWHJYA5XWwM X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 209.85.223.173 Cc: peter.crosthwaite@petalogix.com, crwulff@gmail.com Subject: [Qemu-devel] [RFC v0 09/10] microblaze_generic_fdt: first revision 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 First revision of fdt generic platform for xilinx microblaze platforms. Adds machine model "microblaze-fdt" which can be used along with the --hw-dtb option to lauch dts driven machine models for microblaze platforms. Signed-off-by: Peter A. G. Crosthwaite --- hw/microblaze/Makefile.objs | 1 + hw/microblaze_generic_fdt.c | 378 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 379 insertions(+), 0 deletions(-) create mode 100644 hw/microblaze_generic_fdt.c diff --git a/hw/microblaze/Makefile.objs b/hw/microblaze/Makefile.objs index ef2d6b7..be3aaa5 100644 --- a/hw/microblaze/Makefile.objs +++ b/hw/microblaze/Makefile.objs @@ -1,5 +1,6 @@ obj-y = petalogix_s3adsp1800_mmu.o obj-y += petalogix_ml605_mmu.o +obj-y += microblaze_generic_fdt.o obj-y += microblaze_boot.o obj-y += microblaze_pic_cpu.o diff --git a/hw/microblaze_generic_fdt.c b/hw/microblaze_generic_fdt.c new file mode 100644 index 0000000..1a58210 --- /dev/null +++ b/hw/microblaze_generic_fdt.c @@ -0,0 +1,378 @@ +/* + * Model of Petalogix linux reference design for all boards + * + * Copyright (c) 2009 Edgar E. Iglesias. + * Copyright (c) 2009 Michal Simek. + * Copyright (c) 2012 Peter A.G. Crosthwaite (peter.croshtwaite@petalogix.com) + * Copyright (c) 2012 Petalogix Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "sysbus.h" +#include "net.h" +#include "flash.h" +#include "sysemu.h" +#include "boards.h" +#include "device_tree.h" +#include "exec-memory.h" + +#include "fdt_generic_util.h" +#include "fdt_generic_devices.h" + +#include "microblaze_pic_cpu.h" +#include "microblaze_boot.h" + +#define VAL(name) qemu_devtree_getprop_cell(fdt, node_path, name, 0, false, \ + NULL) + +static void +microblaze_generic_fdt_reset(MicroBlazeCPU *cpu, void *fdt) +{ + CPUMBState *env = &cpu->env; + + char node_path[DT_PATH_LENGTH]; + qemu_devtree_get_node_by_name(fdt, node_path, "cpu@"); + int t; + int use_exc = 0; + + env->pvr.regs[0] = 0; + env->pvr.regs[2] = PVR2_D_OPB_MASK \ + | PVR2_D_LMB_MASK \ + | PVR2_I_OPB_MASK \ + | PVR2_I_LMB_MASK \ + | 0; + + if (VAL("xlnx,pvr")) { + env->sregs[SR_MSR] |= MSR_PVR; + } + + /* Even if we don't have PVR's, we fill out everything + because QEMU will internally follow what the pvr regs + state about the HW. */ + + if (VAL("xlnx,pvr") == 2) { + env->pvr.regs[0] |= PVR0_PVR_FULL_MASK; + } + + if (VAL("xlnx,endianness")) { + env->pvr.regs[0] |= PVR0_ENDI; + } + + if (VAL("xlnx,use-barrel")) { + env->pvr.regs[0] |= PVR0_USE_BARREL_MASK; + env->pvr.regs[2] |= PVR2_USE_BARREL_MASK; + } + + if (VAL("xlnx,use-div")) { + env->pvr.regs[0] |= PVR0_USE_DIV_MASK; + env->pvr.regs[2] |= PVR2_USE_DIV_MASK; + } + + t = VAL("xlnx,use-hw-mul"); + if (t) { + env->pvr.regs[0] |= PVR0_USE_HW_MUL_MASK; + env->pvr.regs[2] |= PVR2_USE_HW_MUL_MASK; + if (t >= 2) { + env->pvr.regs[2] |= PVR2_USE_MUL64_MASK; + } + } + + t = VAL("xlnx,use-fpu"); + if (t) { + env->pvr.regs[0] |= PVR0_USE_FPU_MASK; + env->pvr.regs[2] |= PVR2_USE_FPU_MASK; + if (t > 1) { + env->pvr.regs[2] |= PVR2_USE_FPU2_MASK; + } + } + + if (VAL("xlnx,use-msr-instr")) { + env->pvr.regs[2] |= PVR2_USE_MSR_INSTR; + } + + if (VAL("xlnx,use-pcmp-instr")) { + env->pvr.regs[2] |= PVR2_USE_PCMP_INSTR; + } + + if (VAL("xlnx,opcode-0x0-illegal")) { + env->pvr.regs[2] |= PVR2_OPCODE_0x0_ILL_MASK; + } + + if (VAL("xlnx,unaligned-exceptions")) { + env->pvr.regs[2] |= PVR2_UNALIGNED_EXC_MASK; + use_exc = 1; + } + + if (VAL("xlnx,ill-opcode-exception")) { + env->pvr.regs[2] |= PVR2_ILL_OPCODE_EXC_MASK; + use_exc = 1; + } + + if (VAL("xlnx,iopb-bus-exception")) { + env->pvr.regs[2] |= PVR2_IOPB_BUS_EXC_MASK; + use_exc = 1; + } + + if (VAL("xlnx,dopb-bus-exception")) { + env->pvr.regs[2] |= PVR2_DOPB_BUS_EXC_MASK; + use_exc = 1; + } + + if (VAL("xlnx,div-zero-exception")) { + env->pvr.regs[2] |= PVR2_DIV_ZERO_EXC_MASK; + use_exc = 1; + } + + if (VAL("xlnx,fpu-exception")) { + env->pvr.regs[2] |= PVR2_FPU_EXC_MASK; + use_exc = 1; + } + + env->pvr.regs[0] |= VAL("xlnx,pvr-user1") & 0xff; + env->pvr.regs[1] = VAL("xlnx,pvr-user2"); + + /* MMU regs. */ + t = VAL("xlnx,use-mmu"); + if (use_exc || t) { + env->pvr.regs[0] |= PVR0_USE_EXC_MASK ; + } + + if (t) { + env->pvr.regs[0] |= PVR0_USE_MMU; + } + env->pvr.regs[11] = t << 30; + t = VAL("xlnx,mmu-zones"); + env->pvr.regs[11] |= t << 17; + env->mmu.c_mmu_zones = t; + + t = VAL("xlnx,mmu-tlb-access"); + env->mmu.c_mmu_tlb_access = t; + env->pvr.regs[11] |= t << 22; + + { + char *str; + const struct { + const char *name; + unsigned int arch; + } arch_lookup[] = { + {"virtex2", 0x4}, + {"virtex2pro", 0x5}, + {"spartan3", 0x6}, + {"virtex4", 0x7}, + {"virtex5", 0x8}, + {"spartan3e", 0x9}, + {"spartan3a", 0xa}, + {"spartan3an", 0xb}, + {"spartan3adsp", 0xc}, + {"spartan6", 0xd}, + {"virtex6", 0xe}, + {"spartan2", 0xf0}, + {NULL, 0}, + }; + unsigned int i = 0; + + str = qemu_devtree_getprop(fdt, node_path, "xlnx,family", NULL, + false, NULL); + while (arch_lookup[i].name && str) { + if (strcmp(arch_lookup[i].name, str) == 0) { + break; + } + i++; + } + if (!str || !arch_lookup[i].arch) { + env->pvr.regs[10] = 0x0c000000; /* spartan 3a dsp family. */ + } else { + env->pvr.regs[10] = arch_lookup[i].arch << 24; + } + g_free(str); + } + + { + char *str; + const struct { + const char *name; + unsigned int arch; + } cpu_lookup[] = { + /* These key value are as per MBV field in PVR0 */ + {"5.00.a", 0x01}, + {"5.00.b", 0x02}, + {"5.00.c", 0x03}, + {"6.00.a", 0x04}, + {"6.00.b", 0x06}, + {"7.00.a", 0x05}, + {"7.00.b", 0x07}, + {"7.10.a", 0x08}, + {"7.10.b", 0x09}, + {"7.10.c", 0x0a}, + {"7.10.d", 0x0b}, + {"7.20.a", 0x0c}, + {"7.20.b", 0x0d}, + {"7.20.c", 0x0e}, + {"7.20.d", 0x0f}, + {"7.30.a", 0x10}, + {"7.30.b", 0x11}, + {"8.00.a", 0x12}, + {"8.00.b", 0x13}, + {"8.10.a", 0x14}, + /* FIXME There is no keycode defined in MBV for these versions */ + {"2.10.a", 0x10}, + {"3.00.a", 0x20}, + {"4.00.a", 0x30}, + {"4.00.b", 0x40}, + {NULL, 0}, + }; + unsigned int i = 0; + + str = qemu_devtree_getprop(fdt, node_path, "model", NULL, false, NULL); + + while (cpu_lookup[i].name && str) { + if (strcmp(cpu_lookup[i].name, str + strlen("microblaze,")) == 0) { + break; + } + i++; + } + if (!str || !cpu_lookup[i].arch) { + fprintf(stderr, "unable to find MicroBlaze model.\n"); + env->pvr.regs[0] |= 0xb << 8; + } else { + env->pvr.regs[0] |= cpu_lookup[i].arch << 8; + } + g_free(str); + } + + { + env->pvr.regs[4] = PVR4_USE_ICACHE_MASK + | (21 << 26) /* Tag size. */ + | (4 << 21) + | (11 << 16); + env->pvr.regs[6] = VAL("d-cache-baseaddr"); + env->pvr.regs[7] = VAL("d-cache-highaddr"); + env->pvr.regs[5] = PVR5_USE_DCACHE_MASK + | (21 << 26) /* Tag size. */ + | (4 << 21) + | (11 << 16); + + if (VAL("xlnx,dcache-use-writeback")) { + env->pvr.regs[5] |= PVR5_DCACHE_WRITEBACK_MASK; + } + + env->pvr.regs[8] = VAL("i-cache-baseaddr"); + env->pvr.regs[9] = VAL("i-cache-highaddr"); + } +} + +#define LMB_BRAM_SIZE (128 * 1024) + +#define MACHINE_NAME "microblaze-fdt" + +#ifdef TARGET_WORDS_BIGENDIAN +int endian = 1; +#else +int endian; +#endif + +static void +microblaze_generic_fdt_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) +{ + MicroBlazeCPU *cpu; + MemoryRegion *address_space_mem = get_system_memory(); + MemoryRegion *lmb_bram = g_new(MemoryRegion, 1); + MemoryRegion *ddr_ram = g_new(MemoryRegion, 1); + target_phys_addr_t ram_base; + void *fdt = NULL; + const char *dtb_arg; + QemuOpts *machine_opts; + Error *errp = NULL; + + /* for memory node */ + char node_path[DT_PATH_LENGTH]; + + machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0); + if (!machine_opts) { + goto no_dtb_arg; + } + dtb_arg = qemu_opt_get(machine_opts, "dtb"); + if (!dtb_arg) { + goto no_dtb_arg; + } + + fdt = load_device_tree(dtb_arg, NULL); + if (!fdt) { + hw_error("Error: Unable to load Device Tree %s\n", dtb_arg); + return; + } + + /* init CPUs */ + if (cpu_model == NULL) { + cpu_model = "microblaze"; + } + cpu = cpu_mb_init(cpu_model); + + /* find memory node */ + /* FIXME it could be good to fix case when you don't find memory node */ + qemu_devtree_get_node_by_name(fdt, node_path, "memory@"); + ram_base = qemu_devtree_getprop_cell(fdt, node_path, "reg", 0, + false, &errp); + ram_size = qemu_devtree_getprop_cell(fdt, node_path, "reg", 1, + false, &errp); + assert_no_error(errp); + + /* FIXME: instantiate from FDT like evrything else */ + /* Attach emulated BRAM through the LMB. */ + memory_region_init_ram(lmb_bram, "microblaze_fdt.lmb_bram", LMB_BRAM_SIZE); + vmstate_register_ram_global(lmb_bram); + memory_region_add_subregion(address_space_mem, 0, lmb_bram); + + memory_region_init_ram(ddr_ram, "microblaze_fdt.ddr_ram", ram_size); + vmstate_register_ram_global(ddr_ram); + memory_region_add_subregion(address_space_mem, ram_base, ddr_ram); + + /* Instantiate peripherals from the FDT. */ + fdt_init_destroy_fdti( + fdt_generic_create_machine(fdt, microblaze_pic_init_cpu(&cpu->env))); + + microblaze_load_kernel(cpu, ram_base, ram_size, NULL, + microblaze_generic_fdt_reset, fdt); + return; +no_dtb_arg: + hw_error("DTB must be specified for %s machine model\n", MACHINE_NAME); + return; +} + +static QEMUMachine microblaze_generic_fdt = { + .name = MACHINE_NAME, + .desc = "Petalogix FDT Generic, for all Microblaze MMU boards", + .init = microblaze_generic_fdt_init, +}; + +static void microblaze_fdt_init(void) +{ + qemu_register_machine(µblaze_generic_fdt); +} + +machine_init(microblaze_fdt_init); + +fdt_register_compatibility(simple_bus_fdt_init, "xlnx,compound"); +fdt_register_compatibility_opaque(pflash_cfi01_fdt_init, "cfi-flash", 0, + &endian);