From patchwork Thu Aug 25 06:41:20 2011 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: 111474 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 97E06B6F70 for ; Thu, 25 Aug 2011 16:44:52 +1000 (EST) Received: from localhost ([::1]:46586 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QwTgI-00037c-44 for incoming@patchwork.ozlabs.org; Thu, 25 Aug 2011 02:44:50 -0400 Received: from eggs.gnu.org ([140.186.70.92]:47227) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QwTgA-00035k-VW for qemu-devel@nongnu.org; Thu, 25 Aug 2011 02:44:44 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QwTg4-000478-JN for qemu-devel@nongnu.org; Thu, 25 Aug 2011 02:44:42 -0400 Received: from mail-yi0-f45.google.com ([209.85.218.45]:34522) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QwTg4-0003yc-FY for qemu-devel@nongnu.org; Thu, 25 Aug 2011 02:44:36 -0400 Received: by mail-yi0-f45.google.com with SMTP id 10so1693869yih.4 for ; Wed, 24 Aug 2011 23:44:36 -0700 (PDT) Received: by 10.151.8.5 with SMTP id l5mr446154ybi.300.1314254676194; Wed, 24 Aug 2011 23:44:36 -0700 (PDT) Received: from localhost ([124.148.20.9]) by mx.google.com with ESMTPS id p1sm967715yba.2.2011.08.24.23.44.31 (version=TLSv1/SSLv3 cipher=OTHER); Wed, 24 Aug 2011 23:44:35 -0700 (PDT) From: "Peter A. G. Crosthwaite" To: qemu-devel@nongnu.org, stefanha@linux.vnet.ibm.com, edgar.iglesias@gmail.com, john.williams@petalogix.com, michal.simek@petalogix.com Date: Thu, 25 Aug 2011 16:41:20 +1000 Message-Id: <1314254480-22438-15-git-send-email-peter.crosthwaite@petalogix.com> X-Mailer: git-send-email 1.7.3.2 In-Reply-To: <1314254480-22438-1-git-send-email-peter.crosthwaite@petalogix.com> References: <1314254480-22438-1-git-send-email-peter.crosthwaite@petalogix.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 2) X-Received-From: 209.85.218.45 Cc: "Peter A. G. Crosthwaite" Subject: [Qemu-devel] [RFC PATCH V1 14/14] 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 --- Makefile.target | 1 + hw/microblaze_generic_fdt.c | 439 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 440 insertions(+), 0 deletions(-) create mode 100644 hw/microblaze_generic_fdt.c diff --git a/Makefile.target b/Makefile.target index e280bf6..6a0ee92 100644 --- a/Makefile.target +++ b/Makefile.target @@ -296,6 +296,7 @@ obj-mips-$(CONFIG_FULONG) += bonito.o vt82c686.o mips_fulong2e.o obj-microblaze-y = petalogix_s3adsp1800_mmu.o obj-microblaze-y += petalogix_ml605_mmu.o +obj-microblaze-$(CONFIG_FDT) += microblaze_generic_fdt.o obj-microblaze-y += microblaze_pic_cpu.o obj-microblaze-y += xilinx_intc.o diff --git a/hw/microblaze_generic_fdt.c b/hw/microblaze_generic_fdt.c new file mode 100644 index 0000000..08852ff --- /dev/null +++ b/hw/microblaze_generic_fdt.c @@ -0,0 +1,439 @@ +/* + * Model of Petalogix linux reference design targetting + * Xilinx Spartan 3ADSP-1800 boards. + * + * Copyright (c) 2009 Edgar E. Iglesias. + * Copyright (c) 2009 Michal Simek. + * + * 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. + */ + +/* TODO slim down these includes */ + +#include +#include +#include "sysbus.h" +#include "hw.h" +#include "pc.h" +#include "net.h" +#include "flash.h" +#include "sysemu.h" +#include "devices.h" +#include "boards.h" +#include "device_tree.h" +#include "qdev-addr.h" +#include "loader.h" +#include "elf.h" +#include "fdt_generic_util.h" +#include "fdt_generic_devices.h" + +#include "microblaze_pic_cpu.h" + +#define VAL(name) qemu_devtree_getprop(fdt, NULL, node_path, name, 0, 0) + +static inline void +microblaze_pvr_fdt_init(CPUState *env, void *fdt) +{ + 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; + + { + const 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_string(fdt, node_path, "xlnx,family", 0, + NULL, 0); + 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; + } + + { + const 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_string(fdt, node_path, "model", 0, NULL, 0); + if (str) + str += strlen("microblaze,"); + + while (cpu_lookup[i].name && str) { + if (strcmp(cpu_lookup[i].name, str) == 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; + } + + { + 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) + +static struct +{ + uint32_t bootstrap_pc; + uint32_t cmdline; + uint32_t fdt; + void *vfdt; +} boot_info; + +static void main_cpu_reset(void *opaque) +{ + CPUState *env = opaque; + + cpu_reset(env); + microblaze_pvr_fdt_init(env, boot_info.vfdt); + + env->regs[5] = boot_info.cmdline; + env->regs[7] = boot_info.fdt; + env->sregs[SR_PC] = boot_info.bootstrap_pc; +} + +#ifdef TARGET_WORDS_BIGENDIAN +int endian = 1; +#else +int endian = 0; +#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) +{ + CPUState *env; + int kernel_size; + target_phys_addr_t ram_base; + ram_addr_t phys_lmb_bram; + ram_addr_t phys_ram; + void *fdt = NULL, *kfdt = NULL; + int fdt_size, kfdt_size; + int r; + + /* for memory node */ + char node_path[DT_PATH_LENGTH]; + + const char *dtb = "mb.dtb"; + + /* If a non-default DTB is specified, try to load it first */ + if (qemu_hwdtb) + dtb = qemu_hwdtb; + + fdt = boot_info.vfdt = load_device_tree(dtb, &fdt_size); + if (!fdt) { + fprintf(stderr, "Error: Unable to load Device Tree %s\n", dtb); + return; + } + + /* 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(fdt, NULL, node_path, "reg", 0, 0); + ram_size = qemu_devtree_getprop(fdt, NULL, node_path, "reg", 1, 0); + + /* init CPUs */ + if (cpu_model == NULL) { + cpu_model = "microblaze"; + } + env = cpu_init(cpu_model); + microblaze_pvr_fdt_init(env, fdt); + + qemu_register_reset(main_cpu_reset, env); + + /* Attach emulated BRAM through the LMB. */ + phys_lmb_bram = qemu_ram_alloc(NULL, "mb.lmb", LMB_BRAM_SIZE); + cpu_register_physical_memory(0x00000000, LMB_BRAM_SIZE, + phys_lmb_bram | IO_MEM_RAM); + + phys_ram = qemu_ram_alloc(NULL, "mb.ram", ram_size); + cpu_register_physical_memory(ram_base, ram_size, phys_ram | IO_MEM_RAM); + + /* Instantiate peripherals from the FDT. */ + fdt_init_destroy_fdti( + fdt_generic_create_machine(fdt, microblaze_pic_init_cpu(env)) ); + + if (kernel_filename) { + uint64_t entry, low, high; + int kcmdline_len; + + kernel_size = load_elf(kernel_filename, NULL, NULL, + &entry, &low, &high, endian, ELF_MACHINE, 0); + + /* If we failed loading ELF's try a raw image. */ + if (kernel_size < 0) { + kernel_size = load_image_targphys(kernel_filename, ram_base, + ram_size); + boot_info.bootstrap_pc = ram_base; + high = ram_base + kernel_size; + } + boot_info.bootstrap_pc = (uint32_t)entry; + + kernel_cmdline = fdt_generic_chosen_kcmdline(fdt, kernel_cmdline); + + boot_info.cmdline = high + 8192; + if (kernel_cmdline && (kcmdline_len = strlen(kernel_cmdline))) { + pstrcpy_targphys("cmdline", boot_info.cmdline, 256, kernel_cmdline); + } + /* Provide a device-tree. */ + boot_info.fdt = boot_info.cmdline + 8192; + + if (kernel_cmdline && (kcmdline_len = strlen(kernel_cmdline))) { + r = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", + kernel_cmdline); + if (r < 0) { + fprintf(stderr, "couldn't set /chosen/bootargs\n"); + } + } + + /* Check for a specific device tree intended for the kernel */ + if (qemu_kerndtb) { + if (!strncmp(qemu_kerndtb, "none", 5)) { + fprintf(stderr, "No kernel FDT - use compiled-in FDT\n"); + boot_info.fdt = 0x0; + } else { + kfdt = load_device_tree(qemu_kerndtb, &kfdt_size); + if (!kfdt) { + fprintf(stderr, "Unable to load kernel DTB: %s, " + "reverting to HW DTB\n", qemu_kerndtb); + } else { + dtb = qemu_kerndtb; + fdt = kfdt; + fdt_size = kfdt_size; + } + } + } + if (boot_info.fdt) { + cpu_physical_memory_write (boot_info.fdt, (void *)fdt, fdt_size); + } + } + +} + +static QEMUMachine microblaze_generic_fdt = { + .name = "microblaze-fdt", + .desc = "Petalogix linux refdesign for all 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);