Patchwork [v2,2/2] target-xtensa: add Avnet LX60/LX110/LX200 boards

login
register
mail settings
Submitter Max Filippov
Date Oct. 15, 2011, 10:56 p.m.
Message ID <1318719406-19730-3-git-send-email-jcmvbkbc@gmail.com>
Download mbox | patch
Permalink /patch/120002/
State New
Headers show

Comments

Max Filippov - Oct. 15, 2011, 10:56 p.m.
These boards carry similar hardware: SDRAM (48M for LX110, 64M for LX60,
96M for LX200), 16 Mbyte FLASH, FPGA, 10/100 Mbps Ethernet PHY and 16550
UART. FPGA may be loaded with almost any Tensilica processor. It is also
used to implement Ethernet MAC, e.g. OpenCores 10/100 Mbps Ethernet MAC
and LED/DIP switches access.

Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
---
v1 -> v2 changes: adopt serial_mm_init converted to new memory API

---
 Makefile.target                      |    1 +
 default-configs/xtensa-softmmu.mak   |    3 +
 default-configs/xtensaeb-softmmu.mak |    3 +
 hw/xtensa_lx60.c                     |  233 ++++++++++++++++++++++++++++++++++
 4 files changed, 240 insertions(+), 0 deletions(-)
 create mode 100644 hw/xtensa_lx60.c

Patch

diff --git a/Makefile.target b/Makefile.target
index 752221c..3d94228 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -371,6 +371,7 @@  obj-alpha-y += alpha_pci.o alpha_dp264.o alpha_typhoon.o
 
 obj-xtensa-y += xtensa_pic.o
 obj-xtensa-y += xtensa_sim.o
+obj-xtensa-y += xtensa_lx60.o
 obj-xtensa-y += xtensa-semi.o
 obj-xtensa-y += core-dc232b.o
 obj-xtensa-y += core-fsf.o
diff --git a/default-configs/xtensa-softmmu.mak b/default-configs/xtensa-softmmu.mak
index e5faa09..7f0df34 100644
--- a/default-configs/xtensa-softmmu.mak
+++ b/default-configs/xtensa-softmmu.mak
@@ -1 +1,4 @@ 
 # Default configuration for Xtensa
+
+CONFIG_SERIAL=y
+CONFIG_OPENCORES_ETH=y
diff --git a/default-configs/xtensaeb-softmmu.mak b/default-configs/xtensaeb-softmmu.mak
index e5faa09..7f0df34 100644
--- a/default-configs/xtensaeb-softmmu.mak
+++ b/default-configs/xtensaeb-softmmu.mak
@@ -1 +1,4 @@ 
 # Default configuration for Xtensa
+
+CONFIG_SERIAL=y
+CONFIG_OPENCORES_ETH=y
diff --git a/hw/xtensa_lx60.c b/hw/xtensa_lx60.c
new file mode 100644
index 0000000..3cebca1
--- /dev/null
+++ b/hw/xtensa_lx60.c
@@ -0,0 +1,233 @@ 
+/*
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Open Source and Linux Lab nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "sysemu.h"
+#include "boards.h"
+#include "loader.h"
+#include "elf.h"
+#include "memory.h"
+#include "exec-memory.h"
+#include "pc.h"
+#include "sysbus.h"
+
+typedef struct Lx60FpgaState {
+    MemoryRegion iomem;
+    uint32_t leds;
+    uint32_t switches;
+} Lx60FpgaState;
+
+static void lx60_fpga_reset(void *opaque)
+{
+    Lx60FpgaState *s = opaque;
+
+    s->leds = 0;
+    s->switches = 0;
+}
+
+static uint64_t lx60_fpga_read(void *opaque, target_phys_addr_t addr,
+        unsigned size)
+{
+    Lx60FpgaState *s = opaque;
+
+    switch (addr) {
+    case 0x0: /*build date code*/
+        return 0x27092011;
+
+    case 0x4: /*processor clock frequency, Hz*/
+        return 10000000;
+
+    case 0x8: /*LEDs (off = 0, on = 1)*/
+        return s->leds;
+
+    case 0xc: /*DIP switches (off = 0, on = 1)*/
+        return s->switches;
+    }
+    return 0;
+}
+
+static void lx60_fpga_write(void *opaque, target_phys_addr_t addr,
+        uint64_t val, unsigned size)
+{
+    Lx60FpgaState *s = opaque;
+
+    switch (addr) {
+    case 0x8: /*LEDs (off = 0, on = 1)*/
+        s->leds = val;
+        break;
+
+    case 0x10: /*board reset*/
+        if (val == 0xdead) {
+            qemu_system_reset_request();
+        }
+        break;
+    }
+}
+
+static const MemoryRegionOps lx60_fpga_ops = {
+    .read = lx60_fpga_read,
+    .write = lx60_fpga_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static Lx60FpgaState *lx60_fpga_init(MemoryRegion *address_space,
+        target_phys_addr_t base)
+{
+    Lx60FpgaState *s = g_malloc(sizeof(Lx60FpgaState));
+
+    memory_region_init_io(&s->iomem, &lx60_fpga_ops, s,
+            "lx60-fpga", 0x10000);
+    memory_region_add_subregion(address_space, base, &s->iomem);
+    lx60_fpga_reset(s);
+    qemu_register_reset(lx60_fpga_reset, s);
+    return s;
+}
+
+static void lx60_net_init(MemoryRegion *address_space,
+        target_phys_addr_t base,
+        target_phys_addr_t descriptors,
+        target_phys_addr_t buffers,
+        qemu_irq irq, NICInfo *nd)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    MemoryRegion *ram;
+
+    dev = qdev_create(NULL, "open_eth");
+    qdev_set_nic_properties(dev, nd);
+    qdev_init_nofail(dev);
+
+    s = sysbus_from_qdev(dev);
+    sysbus_connect_irq(s, 0, irq);
+    memory_region_add_subregion(address_space, base,
+            sysbus_mmio_get_region(s, 0));
+    memory_region_add_subregion(address_space, descriptors,
+            sysbus_mmio_get_region(s, 1));
+
+    ram = g_malloc(sizeof(*ram));
+    memory_region_init_ram(ram, NULL, "open_eth.ram", 16384);
+    memory_region_add_subregion(address_space, buffers, ram);
+}
+
+static uint64_t translate_phys_addr(void *env, uint64_t addr)
+{
+    return cpu_get_phys_page_debug(env, addr);
+}
+
+static void lx60_reset(void *env)
+{
+    cpu_reset(env);
+}
+
+static void lx60_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)
+{
+#ifdef TARGET_WORDS_BIGENDIAN
+    int be = 1;
+#else
+    int be = 0;
+#endif
+    MemoryRegion *system_memory = get_system_memory();
+    CPUState *env = NULL;
+    MemoryRegion *ram, *rom, *system_io;
+    int n;
+
+    for (n = 0; n < smp_cpus; n++) {
+        env = cpu_init(cpu_model);
+        if (!env) {
+            fprintf(stderr, "Unable to find CPU definition\n");
+            exit(1);
+        }
+        env->sregs[PRID] = n;
+        qemu_register_reset(lx60_reset, env);
+        /* Need MMU initialized prior to ELF loading,
+         * so that ELF gets loaded into virtual addresses
+         */
+        cpu_reset(env);
+    }
+
+    ram = g_malloc(sizeof(*ram));
+    memory_region_init_ram(ram, NULL, "xtensa.sram", ram_size);
+    memory_region_add_subregion(system_memory, 0, ram);
+
+    rom = g_malloc(sizeof(*rom));
+    memory_region_init_ram(rom, NULL, "xtensa.rom", 0x1000);
+    memory_region_add_subregion(system_memory, 0xfe000000, rom);
+
+    system_io = g_malloc(sizeof(*system_io));
+    memory_region_init(system_io, "system.io", 224 * 1024 * 1024);
+    memory_region_add_subregion(system_memory, 0xf0000000, system_io);
+    lx60_fpga_init(system_io, 0x0d020000);
+    if (nd_table[0].vlan) {
+        lx60_net_init(system_io, 0x0d030000, 0x0d030400, 0x0d800000,
+                xtensa_get_extint(env, 1), nd_table);
+    }
+
+    if (!serial_hds[0]) {
+        serial_hds[0] = qemu_chr_new("serial0", "null", NULL);
+    }
+
+    serial_mm_init(system_io, 0x0d050020, 2, xtensa_get_extint(env, 0),
+            115200, serial_hds[0], DEVICE_NATIVE_ENDIAN);
+
+    if (kernel_filename) {
+        uint64_t elf_entry;
+        uint64_t elf_lowaddr;
+        int success = load_elf(kernel_filename, translate_phys_addr, env,
+                &elf_entry, &elf_lowaddr, NULL, be, ELF_MACHINE, 0);
+        if (success > 0) {
+            env->pc = elf_entry;
+        }
+    }
+}
+
+static void xtensa_lx60_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)
+{
+    if (!cpu_model) {
+        cpu_model = "dc232b";
+    }
+    lx60_init(ram_size, boot_device, kernel_filename, kernel_cmdline,
+            initrd_filename, cpu_model);
+}
+
+static QEMUMachine xtensa_lx60_machine = {
+    .name = "lx60",
+    .desc = "lx60 EVB (dc232b)",
+    .init = xtensa_lx60_init,
+    .max_cpus = 4,
+};
+
+static void xtensa_lx60_machine_init(void)
+{
+    qemu_register_machine(&xtensa_lx60_machine);
+}
+
+machine_init(xtensa_lx60_machine_init);