qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH qemu 3/3] hw/mips/mt7628.c: add mt7628 soc support, add a mt7628


From: ~luhux
Subject: [PATCH qemu 3/3] hw/mips/mt7628.c: add mt7628 soc support, add a mt7628 board VoCore2.
Date: Wed, 18 Jan 2023 17:06:02 +0800

From: LuHui <luhux76@gmail.com>

Signed-off-by: LuHui <luhux76@gmail.com>
---
 MAINTAINERS                             |   1 +
 configs/devices/mips-softmmu/common.mak |   2 +
 hw/mips/Kconfig                         |  11 ++
 hw/mips/meson.build                     |   2 +
 hw/mips/mt7628.c                        | 189 ++++++++++++++++++++++++
 hw/mips/vocore2.c                       | 180 ++++++++++++++++++++++
 include/hw/mips/mt7628.h                |  77 ++++++++++
 7 files changed, 462 insertions(+)
 create mode 100644 hw/mips/mt7628.c
 create mode 100644 hw/mips/vocore2.c
 create mode 100644 include/hw/mips/mt7628.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 41854e939c..1b2f92e078 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1238,6 +1238,7 @@ VoCore2
 M: Lu Hui <luhux76@gmail.com>
 S: Maintained
 F: hw/*/*mt7628*
+F: hw/mips/vocore2.c
 
 Jazz
 M: Hervé Poussineau <hpoussin@reactos.org>
diff --git a/configs/devices/mips-softmmu/common.mak 
b/configs/devices/mips-softmmu/common.mak
index 7da99327a7..e4a5c54635 100644
--- a/configs/devices/mips-softmmu/common.mak
+++ b/configs/devices/mips-softmmu/common.mak
@@ -29,3 +29,5 @@ CONFIG_PCNET_PCI=y
 CONFIG_MIPSSIM=y
 CONFIG_SMBUS_EEPROM=y
 CONFIG_TEST_DEVICES=y
+CONFIG_MT7628=y
+CONFIG_VOCORE2=y
diff --git a/hw/mips/Kconfig b/hw/mips/Kconfig
index da3a37e215..f7faec010c 100644
--- a/hw/mips/Kconfig
+++ b/hw/mips/Kconfig
@@ -10,6 +10,17 @@ config MIPSSIM
     select SERIAL_ISA
     select MIPSNET
 
+config MT7628
+    bool
+    select SERIAL
+    select USB_EHCI
+    select USB_EHCI_SYSBUS
+    select UNIMP
+
+config VOCORE2
+    bool
+    select MT7628
+
 config JAZZ
     bool
     select ISA_BUS
diff --git a/hw/mips/meson.build b/hw/mips/meson.build
index 900613fc08..9ad125a996 100644
--- a/hw/mips/meson.build
+++ b/hw/mips/meson.build
@@ -10,6 +10,8 @@ mips_ss.add(when: 'CONFIG_JAZZ', if_true: files('jazz.c'))
 mips_ss.add(when: 'CONFIG_MIPSSIM', if_true: files('mipssim.c'))
 mips_ss.add(when: 'CONFIG_FULOONG', if_true: files('fuloong2e.c'))
 mips_ss.add(when: 'CONFIG_MIPS_BOSTON', if_true: [files('boston.c'), fdt])
+mips_ss.add(when: 'CONFIG_MT7628', if_true: files('mt7628.c'))
+mips_ss.add(when: 'CONFIG_VOCORE2', if_true: files('vocore2.c'))
 endif
 
 hw_arch += {'mips': mips_ss}
diff --git a/hw/mips/mt7628.c b/hw/mips/mt7628.c
new file mode 100644
index 0000000000..d982b1c704
--- /dev/null
+++ b/hw/mips/mt7628.c
@@ -0,0 +1,189 @@
+/*
+ * QEMU/mt7628 emulation
+ *
+ * Copyright (c) 2023 Lu Hui <luhux76@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that 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.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu/datadir.h"
+#include "hw/clock.h"
+#include "hw/block/flash.h"
+#include "hw/mips/mips.h"
+#include "hw/mips/cpudevs.h"
+#include "hw/mips/bios.h"
+#include "hw/usb/hcd-ehci.h"
+#include "hw/char/serial.h"
+#include "hw/misc/unimp.h"
+#include "hw/mips/mt7628.h"
+#include "sysemu/sysemu.h"
+#include "hw/boards.h"
+#include "hw/loader.h"
+#include "elf.h"
+#include "hw/sysbus.h"
+#include "hw/qdev-properties.h"
+#include "qemu/error-report.h"
+#include "sysemu/qtest.h"
+#include "sysemu/reset.h"
+
+/* data src: linux kernel, openwrt, uboot */
+
+/* irq table */
+enum {
+    IRQ_UART0 = 20,
+    IRQ_UART1 = 21,
+    IRQ_UART2 = 22,
+    IRQ_EHCI = 18
+};
+
+/* Memory map */
+const hwaddr mt7628_memmap[] = {
+    [MT7628_DEV_DDR]          = 0x00000000,
+    [MT7628_DEV_SYSCTRL]      = 0x10000000,
+    [MT7628_DEV_INTC]         = 0x10000200,
+    [MT7628_DEV_UART0]        = 0x10000C00,
+    [MT7628_DEV_UART1]        = 0x10000D00,
+    [MT7628_DEV_UART2]        = 0x10000E00,
+    [MT7628_DEV_EHCI]         = 0x101C0000,
+    [MT7628_DEV_FLASH_DIRECT] = 0x1C000000,
+};
+
+struct mt7628Unimplemented {
+    const char *device_name;
+    hwaddr base;
+    hwaddr size;
+} unimplemented[] = {
+    { "timer",        0x10000100, 0xFF },
+    { "memc",         0x10000300, 0xFF },
+    { "rbus",         0x10000400, 0xFF },
+    { "mips-cnt",     0x10000500, 0xFF },
+    { "gpio",         0x10000600, 0xFF },
+    { "spi-slave",    0x10000700, 0xFF },
+    { "i2c",          0x10000900, 0xFF },
+    { "i2s",          0x10000A00, 0xFF },
+    { "spi-master",   0x10000B00, 0xFF },
+    { "rgctl",        0x10001000, 2 * KiB },
+    { "pcm",          0x10002000, 2 * KiB },
+    { "dma",          0x10002800, 2 * KiB },
+    { "aes",          0x10004000, 4 * KiB },
+    { "pwm",          0x10005000, 4 * KiB },
+    { "ethernet-phy", 0x10100000, 64 * KiB },
+    { "ethernet",     0x10110000, 32 * KiB },
+    { "usb-phy",      0x10120000, 32 * KiB },
+    { "sdxc",         0x10130000, 32 * KiB },
+    { "pcie",         0x10140000, 256 * KiB },
+    { "wlan",         0x10300000, 1 * MiB },
+    { "pcie-direct",  0x20000000, 256 * MiB },
+};
+
+static void mt7628_init(Object *obj)
+{
+    mt7628State *s = MT7628(obj);
+    s->memmap = mt7628_memmap;
+
+    object_initialize_child(obj, "sysctrl", &s->sysctrl, TYPE_MT7628_SYSCTRL);
+    object_initialize_child(obj, "intc", &s->intc, TYPE_MT7628_INTC);
+    if (machine_usb(current_machine)) {
+        object_initialize_child(obj, "ehci", &s->ehci, TYPE_PLATFORM_EHCI);
+    }
+}
+
+static void mt7628_realize(DeviceState *dev, Error **errp)
+{
+    mt7628State *s = MT7628(dev);
+    SysBusDevice *sysbusdev;
+    int i;
+
+    if (!sysbus_realize(SYS_BUS_DEVICE(&s->intc), errp)) {
+        return;
+    }
+    CPUMIPSState *env = &s->cpu->env;
+
+    /* interrupt control */
+    sysbusdev = SYS_BUS_DEVICE(&s->intc);
+    sysbus_mmio_map(sysbusdev, 0, s->memmap[MT7628_DEV_INTC]);
+    sysbus_connect_irq(sysbusdev, 0, env->irq[MT7628_CPU_IRQ_INTC]);
+    qdev_pass_gpios(DEVICE(&s->intc), dev, NULL);
+
+    /* system control */
+    sysbus_realize(SYS_BUS_DEVICE(&s->sysctrl), &error_fatal);
+    sysbus_mmio_map(SYS_BUS_DEVICE(&s->sysctrl), 0,
+                    s->memmap[MT7628_DEV_SYSCTRL]);
+
+    /* serial port */
+    for (i = 0; i < 3; i++) {
+        if (serial_hd(i)) {
+            serial_mm_init(get_system_memory(),
+                           s->memmap[MT7628_DEV_UART0 + i], 2,
+                           qdev_get_gpio_in(dev, IRQ_UART0 + i), 115200,
+                           serial_hd(i), DEVICE_NATIVE_ENDIAN);
+        } else {
+            create_unimplemented_device("uart",
+                                        s->memmap[MT7628_DEV_UART0 + i], 256);
+        }
+    }
+
+    /* usb 2.0 host */
+    if (machine_usb(current_machine)) {
+        sysbus_realize(SYS_BUS_DEVICE(&s->ehci), &error_fatal);
+        sysbus_mmio_map(SYS_BUS_DEVICE(&s->ehci), 0,
+                        s->memmap[MT7628_DEV_EHCI]);
+        sysbus_connect_irq(SYS_BUS_DEVICE(&s->ehci), 0,
+                           qdev_get_gpio_in(dev, IRQ_EHCI));
+    } else {
+        create_unimplemented_device("ehci", s->memmap[MT7628_DEV_EHCI],
+                                    256 * KiB);
+    }
+
+    /* flash direct access */
+    DriveInfo *dinfo = drive_get(IF_PFLASH, 0, 0);
+    if (dinfo) {
+        pflash_cfi01_register(s->memmap[MT7628_DEV_FLASH_DIRECT],
+                              "mt7628.flash0", 4 * MiB,
+                              dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
+                              4096, 4, 0, 0, 0, 0, 0);
+    } else {
+        create_unimplemented_device("flash-direct",
+                                    s->memmap[MT7628_DEV_FLASH_DIRECT],
+                                    4 * MiB);
+    }
+
+    /* Unimplemented devices */
+    for (i = 0; i < ARRAY_SIZE(unimplemented); i++) {
+        create_unimplemented_device(unimplemented[i].device_name,
+                                    unimplemented[i].base,
+                                    unimplemented[i].size);
+    }
+}
+
+static void mt7628_class_init(ObjectClass *oc, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+    dc->realize = mt7628_realize;
+    dc->user_creatable = false;
+}
+
+static const TypeInfo mt7628_type_info = {
+    .name = TYPE_MT7628,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(mt7628State),
+    .instance_init = mt7628_init,
+    .class_init = mt7628_class_init,
+};
+
+static void mt7628_register_types(void)
+{
+    type_register_static(&mt7628_type_info);
+}
+
+type_init(mt7628_register_types);
diff --git a/hw/mips/vocore2.c b/hw/mips/vocore2.c
new file mode 100644
index 0000000000..e9662224fd
--- /dev/null
+++ b/hw/mips/vocore2.c
@@ -0,0 +1,180 @@
+/*
+ * QEMU/mt7628 emulation
+ *
+ * Copyright (c) 2023 Lu Hui <luhux76@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that 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.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu/datadir.h"
+#include "hw/clock.h"
+#include "hw/mips/mips.h"
+#include "hw/mips/cpudevs.h"
+#include "hw/mips/mt7628.h"
+#include "sysemu/sysemu.h"
+#include "hw/boards.h"
+#include "hw/mips/bios.h"
+#include "hw/loader.h"
+#include "elf.h"
+#include "hw/sysbus.h"
+#include "hw/qdev-properties.h"
+#include "hw/qdev-clock.h"
+#include "qemu/error-report.h"
+#include "sysemu/qtest.h"
+#include "sysemu/reset.h"
+
+static struct _loaderparams {
+    int ram_size;
+    const char *kernel_filename;
+    const char *kernel_cmdline;
+    const char *initrd_filename;
+} loaderparams;
+
+typedef struct ResetData {
+    MIPSCPU *cpu;
+    uint64_t vector;
+} ResetData;
+
+static uint64_t load_kernel(void)
+{
+    uint64_t entry, kernel_high, initrd_size;
+    long kernel_size;
+    ram_addr_t initrd_offset;
+
+    kernel_size = load_elf(loaderparams.kernel_filename, NULL,
+                           cpu_mips_kseg0_to_phys, NULL,
+                           &entry, NULL,
+                           &kernel_high, NULL, 0, EM_MIPS, 1, 0);
+    if (kernel_size < 0) {
+        error_report("could not load kernel '%s': %s",
+                     loaderparams.kernel_filename,
+                     load_elf_strerror(kernel_size));
+        exit(1);
+    }
+
+    /* load initrd */
+    initrd_size = 0;
+    initrd_offset = 0;
+    if (loaderparams.initrd_filename) {
+        initrd_size = get_image_size(loaderparams.initrd_filename);
+        if (initrd_size > 0) {
+            initrd_offset = ROUND_UP(kernel_high, INITRD_PAGE_SIZE);
+            if (initrd_offset + initrd_size > loaderparams.ram_size) {
+                error_report("memory too small for initial ram disk '%s'",
+                             loaderparams.initrd_filename);
+                exit(1);
+            }
+            initrd_size = load_image_targphys(loaderparams.initrd_filename,
+                                       initrd_offset,
+                                       loaderparams.ram_size - initrd_offset);
+        }
+        if (initrd_size == (target_ulong)-1) {
+            error_report("could not load initial ram disk '%s'",
+                         loaderparams.initrd_filename);
+            exit(1);
+        }
+    }
+    return entry;
+}
+
+static void main_cpu_reset(void *opaque)
+{
+    ResetData *s = (ResetData *) opaque;
+    CPUMIPSState *env = &s->cpu->env;
+
+    cpu_reset(CPU(s->cpu));
+    env->active_tc.PC = s->vector & ~(target_ulong) 1;
+    if (s->vector & 1) {
+        env->hflags |= MIPS_HFLAG_M16;
+    }
+}
+
+static void vocore2_init(MachineState *machine)
+{
+    const char *kernel_filename = machine->kernel_filename;
+    const char *kernel_cmdline = machine->kernel_cmdline;
+    const char *initrd_filename = machine->initrd_filename;
+    mt7628State *mt7628;
+    Clock *cpuclk;
+    MIPSCPU *cpu;
+    ResetData *reset_info;
+
+    /* BIOS is not supported by this board */
+    if (machine->firmware) {
+        error_report("BIOS not supported for this machine");
+        exit(1);
+    }
+
+    /* CPU limit */
+    if (strcmp(machine->cpu_type, MIPS_CPU_TYPE_NAME("24KEc")) != 0) {
+        error_report("This board can only be used with 24KEc CPU");
+        exit(1);
+    }
+
+    /* RAM limit */
+    if (machine->ram_size > 256 * MiB) {
+        error_report("mt7628: memory size must not exceed 256MiB");
+    }
+
+    mt7628 = MT7628(object_new(TYPE_MT7628));
+    object_property_add_child(OBJECT(machine), "soc", OBJECT(mt7628));
+    object_unref(OBJECT(mt7628));
+
+    /* CPU Clock */
+    cpuclk = clock_new(OBJECT(machine), "cpu-refclk");
+    /* xtal 40Mhz -> cpu 580Mhz (VoCore2 use this) */
+    /* xtal 25Mhz -> cpu 575Mhz */
+    clock_set_hz(cpuclk, 580000000);
+
+    /* CPU */
+    cpu = mips_cpu_create_with_clock(machine->cpu_type, cpuclk);
+    cpu_mips_irq_init_cpu(cpu);
+    cpu_mips_clock_init(cpu);
+    mt7628->cpu = cpu;
+
+    /* Mark mt7628 object realized */
+    qdev_realize(DEVICE(mt7628), NULL, &error_abort);
+
+    /* DDR */
+    memory_region_add_subregion(get_system_memory(),
+                                mt7628->memmap[MT7628_DEV_DDR],
+                                machine->ram);
+
+    /* Load kernel to RAM & goto kernel */
+    reset_info = g_new0(ResetData, 1);
+    reset_info->cpu = cpu;
+    reset_info->vector = reset_info->cpu->env.active_tc.PC;
+    qemu_register_reset(main_cpu_reset, reset_info);
+    if (kernel_filename) {
+        loaderparams.ram_size = machine->ram_size;
+        loaderparams.kernel_filename = kernel_filename;
+        loaderparams.kernel_cmdline = kernel_cmdline;
+        loaderparams.initrd_filename = initrd_filename;
+        reset_info->vector = load_kernel();
+    }
+    /* TODO: boot from flash */
+}
+
+static void vocore2_machine_init(MachineClass *mc)
+{
+    mc->desc = "VoCore2 (24KEc)";
+    mc->init = vocore2_init;
+    mc->default_cpu_type = MIPS_CPU_TYPE_NAME("24KEc");
+    mc->default_ram_id = "vocore2.ram";
+    mc->default_ram_size = 128 * MiB;
+    mc->min_cpus = 1;
+    mc->max_cpus = 1;
+    mc->default_cpus = 1;
+}
+
+DEFINE_MACHINE("vocore2", vocore2_machine_init)
diff --git a/include/hw/mips/mt7628.h b/include/hw/mips/mt7628.h
new file mode 100644
index 0000000000..2570f87846
--- /dev/null
+++ b/include/hw/mips/mt7628.h
@@ -0,0 +1,77 @@
+/*
+ * MT7628 System on Chip emulation
+ *
+ * Copyright (C) 2023 Lu Hui <luhux76@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef HW_MIPS_MT7628_H
+#define HW_MIPS_MT7628_H
+
+#include "qom/object.h"
+#include "hw/mips/mips.h"
+#include "hw/mips/cpudevs.h"
+#include "hw/mips/bios.h"
+#include "hw/usb/hcd-ehci.h"
+#include "hw/misc/mt7628-sysctrl.h"
+#include "hw/intc/mt7628-intc.h"
+
+/**
+ * MT7628 device list
+ *
+ * This enumeration is can be used refer to a particular device in the
+ * MT7628 SoC. For example, the physical memory base address for
+ * each device can be found in the mt7628State object in the memmap member
+ * using the device enum value as index.
+ *
+ * @see mt7628State
+ */
+enum {
+    MT7628_DEV_DDR,
+    MT7628_DEV_SYSCTRL,
+    MT7628_DEV_INTC,
+    MT7628_DEV_UART0,
+    MT7628_DEV_UART1,
+    MT7628_DEV_UART2,
+    MT7628_DEV_EHCI,
+    MT7628_DEV_FLASH_DIRECT,
+};
+
+
+/* mt7628 cpu interrupt table */
+
+
+enum {
+    MT7628_CPU_IRQ_INTC = 2,
+    MT7628_CPU_IRQ_PCIE = 4,
+};
+
+#define TYPE_MT7628 "mt7628"
+OBJECT_DECLARE_SIMPLE_TYPE(mt7628State, MT7628)
+
+struct mt7628State {
+    /*< private >*/
+    DeviceState parent_obj;
+    /*< public >*/
+
+    MIPSCPU *cpu;
+    const hwaddr *memmap;
+    mt7628SysCtrlState sysctrl;
+    mt7628intcState intc;
+    EHCISysBusState ehci;
+    MemoryRegion flash_direct;
+};
+
+#endif /* HW_MIPS_MT7628_H */
-- 
2.34.5



reply via email to

[Prev in Thread] Current Thread [Next in Thread]