1a8a506c3SXiaojuan Yang /* SPDX-License-Identifier: GPL-2.0-or-later */ 2a8a506c3SXiaojuan Yang /* 3a8a506c3SXiaojuan Yang * QEMU loongson 3a5000 develop board emulation 4a8a506c3SXiaojuan Yang * 5a8a506c3SXiaojuan Yang * Copyright (c) 2021 Loongson Technology Corporation Limited 6a8a506c3SXiaojuan Yang */ 7a8a506c3SXiaojuan Yang #include "qemu/osdep.h" 8a8a506c3SXiaojuan Yang #include "qemu/units.h" 9a8a506c3SXiaojuan Yang #include "qemu/datadir.h" 10a8a506c3SXiaojuan Yang #include "qapi/error.h" 11a8a506c3SXiaojuan Yang #include "hw/boards.h" 12dc93b8dfSXiaojuan Yang #include "hw/char/serial.h" 13a8a506c3SXiaojuan Yang #include "sysemu/sysemu.h" 14a8a506c3SXiaojuan Yang #include "sysemu/qtest.h" 15a8a506c3SXiaojuan Yang #include "sysemu/runstate.h" 16a8a506c3SXiaojuan Yang #include "sysemu/reset.h" 17a8a506c3SXiaojuan Yang #include "sysemu/rtc.h" 18a8a506c3SXiaojuan Yang #include "hw/loongarch/virt.h" 19a8a506c3SXiaojuan Yang #include "exec/address-spaces.h" 20dc93b8dfSXiaojuan Yang #include "hw/irq.h" 21dc93b8dfSXiaojuan Yang #include "net/net.h" 2269d9c74fSXiaojuan Yang #include "hw/intc/loongarch_ipi.h" 2369d9c74fSXiaojuan Yang #include "hw/intc/loongarch_extioi.h" 2469d9c74fSXiaojuan Yang #include "hw/intc/loongarch_pch_pic.h" 2569d9c74fSXiaojuan Yang #include "hw/intc/loongarch_pch_msi.h" 2669d9c74fSXiaojuan Yang #include "hw/pci-host/ls7a.h" 27dc93b8dfSXiaojuan Yang #include "hw/pci-host/gpex.h" 28dc93b8dfSXiaojuan Yang #include "hw/misc/unimp.h" 2969d9c74fSXiaojuan Yang 30a8a506c3SXiaojuan Yang #include "target/loongarch/cpu.h" 31a8a506c3SXiaojuan Yang 32dc93b8dfSXiaojuan Yang static void loongarch_devices_init(DeviceState *pch_pic) 33dc93b8dfSXiaojuan Yang { 34dc93b8dfSXiaojuan Yang DeviceState *gpex_dev; 35dc93b8dfSXiaojuan Yang SysBusDevice *d; 36dc93b8dfSXiaojuan Yang PCIBus *pci_bus; 37dc93b8dfSXiaojuan Yang MemoryRegion *ecam_alias, *ecam_reg, *pio_alias, *pio_reg; 38dc93b8dfSXiaojuan Yang MemoryRegion *mmio_alias, *mmio_reg; 39dc93b8dfSXiaojuan Yang int i; 40dc93b8dfSXiaojuan Yang 41dc93b8dfSXiaojuan Yang gpex_dev = qdev_new(TYPE_GPEX_HOST); 42dc93b8dfSXiaojuan Yang d = SYS_BUS_DEVICE(gpex_dev); 43dc93b8dfSXiaojuan Yang sysbus_realize_and_unref(d, &error_fatal); 44dc93b8dfSXiaojuan Yang pci_bus = PCI_HOST_BRIDGE(gpex_dev)->bus; 45dc93b8dfSXiaojuan Yang 46dc93b8dfSXiaojuan Yang /* Map only part size_ecam bytes of ECAM space */ 47dc93b8dfSXiaojuan Yang ecam_alias = g_new0(MemoryRegion, 1); 48dc93b8dfSXiaojuan Yang ecam_reg = sysbus_mmio_get_region(d, 0); 49dc93b8dfSXiaojuan Yang memory_region_init_alias(ecam_alias, OBJECT(gpex_dev), "pcie-ecam", 50dc93b8dfSXiaojuan Yang ecam_reg, 0, LS_PCIECFG_SIZE); 51dc93b8dfSXiaojuan Yang memory_region_add_subregion(get_system_memory(), LS_PCIECFG_BASE, 52dc93b8dfSXiaojuan Yang ecam_alias); 53dc93b8dfSXiaojuan Yang 54dc93b8dfSXiaojuan Yang /* Map PCI mem space */ 55dc93b8dfSXiaojuan Yang mmio_alias = g_new0(MemoryRegion, 1); 56dc93b8dfSXiaojuan Yang mmio_reg = sysbus_mmio_get_region(d, 1); 57dc93b8dfSXiaojuan Yang memory_region_init_alias(mmio_alias, OBJECT(gpex_dev), "pcie-mmio", 58dc93b8dfSXiaojuan Yang mmio_reg, LS7A_PCI_MEM_BASE, LS7A_PCI_MEM_SIZE); 59dc93b8dfSXiaojuan Yang memory_region_add_subregion(get_system_memory(), LS7A_PCI_MEM_BASE, 60dc93b8dfSXiaojuan Yang mmio_alias); 61dc93b8dfSXiaojuan Yang 62dc93b8dfSXiaojuan Yang /* Map PCI IO port space. */ 63dc93b8dfSXiaojuan Yang pio_alias = g_new0(MemoryRegion, 1); 64dc93b8dfSXiaojuan Yang pio_reg = sysbus_mmio_get_region(d, 2); 65dc93b8dfSXiaojuan Yang memory_region_init_alias(pio_alias, OBJECT(gpex_dev), "pcie-io", pio_reg, 66dc93b8dfSXiaojuan Yang LS7A_PCI_IO_OFFSET, LS7A_PCI_IO_SIZE); 67dc93b8dfSXiaojuan Yang memory_region_add_subregion(get_system_memory(), LS7A_PCI_IO_BASE, 68dc93b8dfSXiaojuan Yang pio_alias); 69dc93b8dfSXiaojuan Yang 70dc93b8dfSXiaojuan Yang for (i = 0; i < GPEX_NUM_IRQS; i++) { 71dc93b8dfSXiaojuan Yang sysbus_connect_irq(d, i, 72dc93b8dfSXiaojuan Yang qdev_get_gpio_in(pch_pic, 16 + i)); 73dc93b8dfSXiaojuan Yang gpex_set_irq_num(GPEX_HOST(gpex_dev), i, 16 + i); 74dc93b8dfSXiaojuan Yang } 75dc93b8dfSXiaojuan Yang 76dc93b8dfSXiaojuan Yang serial_mm_init(get_system_memory(), LS7A_UART_BASE, 0, 77dc93b8dfSXiaojuan Yang qdev_get_gpio_in(pch_pic, 78dc93b8dfSXiaojuan Yang LS7A_UART_IRQ - PCH_PIC_IRQ_OFFSET), 79dc93b8dfSXiaojuan Yang 115200, serial_hd(0), DEVICE_LITTLE_ENDIAN); 80dc93b8dfSXiaojuan Yang 81dc93b8dfSXiaojuan Yang /* Network init */ 82dc93b8dfSXiaojuan Yang for (i = 0; i < nb_nics; i++) { 83dc93b8dfSXiaojuan Yang NICInfo *nd = &nd_table[i]; 84dc93b8dfSXiaojuan Yang 85dc93b8dfSXiaojuan Yang if (!nd->model) { 86dc93b8dfSXiaojuan Yang nd->model = g_strdup("virtio"); 87dc93b8dfSXiaojuan Yang } 88dc93b8dfSXiaojuan Yang 89dc93b8dfSXiaojuan Yang pci_nic_init_nofail(nd, pci_bus, nd->model, NULL); 90dc93b8dfSXiaojuan Yang } 91dc93b8dfSXiaojuan Yang 92dc93b8dfSXiaojuan Yang /* VGA setup */ 93dc93b8dfSXiaojuan Yang pci_vga_init(pci_bus); 94dc93b8dfSXiaojuan Yang 95dc93b8dfSXiaojuan Yang /* 96dc93b8dfSXiaojuan Yang * There are some invalid guest memory access. 97dc93b8dfSXiaojuan Yang * Create some unimplemented devices to emulate this. 98dc93b8dfSXiaojuan Yang */ 99dc93b8dfSXiaojuan Yang create_unimplemented_device("pci-dma-cfg", 0x1001041c, 0x4); 100c117f68aSXiaojuan Yang sysbus_create_simple("ls7a_rtc", LS7A_RTC_REG_BASE, 101c117f68aSXiaojuan Yang qdev_get_gpio_in(pch_pic, 102c117f68aSXiaojuan Yang LS7A_RTC_IRQ - PCH_PIC_IRQ_OFFSET)); 103dc93b8dfSXiaojuan Yang } 104dc93b8dfSXiaojuan Yang 10569d9c74fSXiaojuan Yang static void loongarch_irq_init(LoongArchMachineState *lams) 10669d9c74fSXiaojuan Yang { 10769d9c74fSXiaojuan Yang MachineState *ms = MACHINE(lams); 10869d9c74fSXiaojuan Yang DeviceState *pch_pic, *pch_msi, *cpudev; 10969d9c74fSXiaojuan Yang DeviceState *ipi, *extioi; 11069d9c74fSXiaojuan Yang SysBusDevice *d; 11169d9c74fSXiaojuan Yang LoongArchCPU *lacpu; 11269d9c74fSXiaojuan Yang CPULoongArchState *env; 11369d9c74fSXiaojuan Yang CPUState *cpu_state; 11469d9c74fSXiaojuan Yang int cpu, pin, i; 11569d9c74fSXiaojuan Yang 11669d9c74fSXiaojuan Yang ipi = qdev_new(TYPE_LOONGARCH_IPI); 11769d9c74fSXiaojuan Yang sysbus_realize_and_unref(SYS_BUS_DEVICE(ipi), &error_fatal); 11869d9c74fSXiaojuan Yang 11969d9c74fSXiaojuan Yang extioi = qdev_new(TYPE_LOONGARCH_EXTIOI); 12069d9c74fSXiaojuan Yang sysbus_realize_and_unref(SYS_BUS_DEVICE(extioi), &error_fatal); 12169d9c74fSXiaojuan Yang 12269d9c74fSXiaojuan Yang /* 12369d9c74fSXiaojuan Yang * The connection of interrupts: 12469d9c74fSXiaojuan Yang * +-----+ +---------+ +-------+ 12569d9c74fSXiaojuan Yang * | IPI |--> | CPUINTC | <-- | Timer | 12669d9c74fSXiaojuan Yang * +-----+ +---------+ +-------+ 12769d9c74fSXiaojuan Yang * ^ 12869d9c74fSXiaojuan Yang * | 12969d9c74fSXiaojuan Yang * +---------+ 13069d9c74fSXiaojuan Yang * | EIOINTC | 13169d9c74fSXiaojuan Yang * +---------+ 13269d9c74fSXiaojuan Yang * ^ ^ 13369d9c74fSXiaojuan Yang * | | 13469d9c74fSXiaojuan Yang * +---------+ +---------+ 13569d9c74fSXiaojuan Yang * | PCH-PIC | | PCH-MSI | 13669d9c74fSXiaojuan Yang * +---------+ +---------+ 13769d9c74fSXiaojuan Yang * ^ ^ ^ 13869d9c74fSXiaojuan Yang * | | | 13969d9c74fSXiaojuan Yang * +--------+ +---------+ +---------+ 14069d9c74fSXiaojuan Yang * | UARTs | | Devices | | Devices | 14169d9c74fSXiaojuan Yang * +--------+ +---------+ +---------+ 14269d9c74fSXiaojuan Yang */ 14369d9c74fSXiaojuan Yang for (cpu = 0; cpu < ms->smp.cpus; cpu++) { 14469d9c74fSXiaojuan Yang cpu_state = qemu_get_cpu(cpu); 14569d9c74fSXiaojuan Yang cpudev = DEVICE(cpu_state); 14669d9c74fSXiaojuan Yang lacpu = LOONGARCH_CPU(cpu_state); 14769d9c74fSXiaojuan Yang env = &(lacpu->env); 14869d9c74fSXiaojuan Yang 14969d9c74fSXiaojuan Yang /* connect ipi irq to cpu irq */ 15069d9c74fSXiaojuan Yang qdev_connect_gpio_out(ipi, cpu, qdev_get_gpio_in(cpudev, IRQ_IPI)); 15169d9c74fSXiaojuan Yang /* IPI iocsr memory region */ 15269d9c74fSXiaojuan Yang memory_region_add_subregion(&env->system_iocsr, SMP_IPI_MAILBOX, 15369d9c74fSXiaojuan Yang sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 15469d9c74fSXiaojuan Yang cpu)); 15569d9c74fSXiaojuan Yang /* extioi iocsr memory region */ 15669d9c74fSXiaojuan Yang memory_region_add_subregion(&env->system_iocsr, APIC_BASE, 15769d9c74fSXiaojuan Yang sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 15869d9c74fSXiaojuan Yang cpu)); 15969d9c74fSXiaojuan Yang } 16069d9c74fSXiaojuan Yang 16169d9c74fSXiaojuan Yang /* 16269d9c74fSXiaojuan Yang * connect ext irq to the cpu irq 16369d9c74fSXiaojuan Yang * cpu_pin[9:2] <= intc_pin[7:0] 16469d9c74fSXiaojuan Yang */ 16569d9c74fSXiaojuan Yang for (cpu = 0; cpu < ms->smp.cpus; cpu++) { 16669d9c74fSXiaojuan Yang cpudev = DEVICE(qemu_get_cpu(cpu)); 16769d9c74fSXiaojuan Yang for (pin = 0; pin < LS3A_INTC_IP; pin++) { 16869d9c74fSXiaojuan Yang qdev_connect_gpio_out(extioi, (cpu * 8 + pin), 16969d9c74fSXiaojuan Yang qdev_get_gpio_in(cpudev, pin + 2)); 17069d9c74fSXiaojuan Yang } 17169d9c74fSXiaojuan Yang } 17269d9c74fSXiaojuan Yang 17369d9c74fSXiaojuan Yang pch_pic = qdev_new(TYPE_LOONGARCH_PCH_PIC); 17469d9c74fSXiaojuan Yang d = SYS_BUS_DEVICE(pch_pic); 17569d9c74fSXiaojuan Yang sysbus_realize_and_unref(d, &error_fatal); 17669d9c74fSXiaojuan Yang memory_region_add_subregion(get_system_memory(), LS7A_IOAPIC_REG_BASE, 17769d9c74fSXiaojuan Yang sysbus_mmio_get_region(d, 0)); 17869d9c74fSXiaojuan Yang memory_region_add_subregion(get_system_memory(), 17969d9c74fSXiaojuan Yang LS7A_IOAPIC_REG_BASE + PCH_PIC_ROUTE_ENTRY_OFFSET, 18069d9c74fSXiaojuan Yang sysbus_mmio_get_region(d, 1)); 18169d9c74fSXiaojuan Yang memory_region_add_subregion(get_system_memory(), 18269d9c74fSXiaojuan Yang LS7A_IOAPIC_REG_BASE + PCH_PIC_INT_STATUS_LO, 18369d9c74fSXiaojuan Yang sysbus_mmio_get_region(d, 2)); 18469d9c74fSXiaojuan Yang 18569d9c74fSXiaojuan Yang /* Connect 64 pch_pic irqs to extioi */ 18669d9c74fSXiaojuan Yang for (int i = 0; i < PCH_PIC_IRQ_NUM; i++) { 18769d9c74fSXiaojuan Yang qdev_connect_gpio_out(DEVICE(d), i, qdev_get_gpio_in(extioi, i)); 18869d9c74fSXiaojuan Yang } 18969d9c74fSXiaojuan Yang 19069d9c74fSXiaojuan Yang pch_msi = qdev_new(TYPE_LOONGARCH_PCH_MSI); 19169d9c74fSXiaojuan Yang d = SYS_BUS_DEVICE(pch_msi); 19269d9c74fSXiaojuan Yang sysbus_realize_and_unref(d, &error_fatal); 19369d9c74fSXiaojuan Yang sysbus_mmio_map(d, 0, LS7A_PCH_MSI_ADDR_LOW); 19469d9c74fSXiaojuan Yang for (i = 0; i < PCH_MSI_IRQ_NUM; i++) { 19569d9c74fSXiaojuan Yang /* Connect 192 pch_msi irqs to extioi */ 19669d9c74fSXiaojuan Yang qdev_connect_gpio_out(DEVICE(d), i, 19769d9c74fSXiaojuan Yang qdev_get_gpio_in(extioi, i + PCH_MSI_IRQ_START)); 19869d9c74fSXiaojuan Yang } 199dc93b8dfSXiaojuan Yang 200dc93b8dfSXiaojuan Yang loongarch_devices_init(pch_pic); 20169d9c74fSXiaojuan Yang } 20269d9c74fSXiaojuan Yang 203a8a506c3SXiaojuan Yang static void loongarch_init(MachineState *machine) 204a8a506c3SXiaojuan Yang { 205a8a506c3SXiaojuan Yang const char *cpu_model = machine->cpu_type; 206a8a506c3SXiaojuan Yang ram_addr_t offset = 0; 207a8a506c3SXiaojuan Yang ram_addr_t ram_size = machine->ram_size; 208a8a506c3SXiaojuan Yang uint64_t highram_size = 0; 209a8a506c3SXiaojuan Yang MemoryRegion *address_space_mem = get_system_memory(); 210a8a506c3SXiaojuan Yang LoongArchMachineState *lams = LOONGARCH_MACHINE(machine); 211a8a506c3SXiaojuan Yang int i; 212a8a506c3SXiaojuan Yang 213a8a506c3SXiaojuan Yang if (!cpu_model) { 214a8a506c3SXiaojuan Yang cpu_model = LOONGARCH_CPU_TYPE_NAME("la464"); 215a8a506c3SXiaojuan Yang } 216a8a506c3SXiaojuan Yang 217a8a506c3SXiaojuan Yang if (!strstr(cpu_model, "la464")) { 218a8a506c3SXiaojuan Yang error_report("LoongArch/TCG needs cpu type la464"); 219a8a506c3SXiaojuan Yang exit(1); 220a8a506c3SXiaojuan Yang } 221a8a506c3SXiaojuan Yang 222a8a506c3SXiaojuan Yang if (ram_size < 1 * GiB) { 223a8a506c3SXiaojuan Yang error_report("ram_size must be greater than 1G."); 224a8a506c3SXiaojuan Yang exit(1); 225a8a506c3SXiaojuan Yang } 226a8a506c3SXiaojuan Yang 227a8a506c3SXiaojuan Yang /* Init CPUs */ 228a8a506c3SXiaojuan Yang for (i = 0; i < machine->smp.cpus; i++) { 229a8a506c3SXiaojuan Yang cpu_create(machine->cpu_type); 230a8a506c3SXiaojuan Yang } 231a8a506c3SXiaojuan Yang 232a8a506c3SXiaojuan Yang /* Add memory region */ 233a8a506c3SXiaojuan Yang memory_region_init_alias(&lams->lowmem, NULL, "loongarch.lowram", 234a8a506c3SXiaojuan Yang machine->ram, 0, 256 * MiB); 235a8a506c3SXiaojuan Yang memory_region_add_subregion(address_space_mem, offset, &lams->lowmem); 236a8a506c3SXiaojuan Yang offset += 256 * MiB; 237a8a506c3SXiaojuan Yang 238a8a506c3SXiaojuan Yang highram_size = ram_size - 256 * MiB; 239a8a506c3SXiaojuan Yang memory_region_init_alias(&lams->highmem, NULL, "loongarch.highmem", 240a8a506c3SXiaojuan Yang machine->ram, offset, highram_size); 241a8a506c3SXiaojuan Yang memory_region_add_subregion(address_space_mem, 0x90000000, &lams->highmem); 242a8a506c3SXiaojuan Yang 243a8a506c3SXiaojuan Yang /* Add isa io region */ 244a8a506c3SXiaojuan Yang memory_region_init_alias(&lams->isa_io, NULL, "isa-io", 245a8a506c3SXiaojuan Yang get_system_io(), 0, LOONGARCH_ISA_IO_SIZE); 246a8a506c3SXiaojuan Yang memory_region_add_subregion(address_space_mem, LOONGARCH_ISA_IO_BASE, 247a8a506c3SXiaojuan Yang &lams->isa_io); 24869d9c74fSXiaojuan Yang /* Initialize the IO interrupt subsystem */ 24969d9c74fSXiaojuan Yang loongarch_irq_init(lams); 250a8a506c3SXiaojuan Yang } 251a8a506c3SXiaojuan Yang 252a8a506c3SXiaojuan Yang static void loongarch_class_init(ObjectClass *oc, void *data) 253a8a506c3SXiaojuan Yang { 254a8a506c3SXiaojuan Yang MachineClass *mc = MACHINE_CLASS(oc); 255a8a506c3SXiaojuan Yang 256a8a506c3SXiaojuan Yang mc->desc = "Loongson-3A5000 LS7A1000 machine"; 257a8a506c3SXiaojuan Yang mc->init = loongarch_init; 258a8a506c3SXiaojuan Yang mc->default_ram_size = 1 * GiB; 259a8a506c3SXiaojuan Yang mc->default_cpu_type = LOONGARCH_CPU_TYPE_NAME("la464"); 260a8a506c3SXiaojuan Yang mc->default_ram_id = "loongarch.ram"; 261a8a506c3SXiaojuan Yang mc->max_cpus = LOONGARCH_MAX_VCPUS; 262a8a506c3SXiaojuan Yang mc->is_default = 1; 263a8a506c3SXiaojuan Yang mc->default_kernel_irqchip_split = false; 264a8a506c3SXiaojuan Yang mc->block_default_type = IF_VIRTIO; 265a8a506c3SXiaojuan Yang mc->default_boot_order = "c"; 266a8a506c3SXiaojuan Yang mc->no_cdrom = 1; 267a8a506c3SXiaojuan Yang } 268a8a506c3SXiaojuan Yang 269a8a506c3SXiaojuan Yang static const TypeInfo loongarch_machine_types[] = { 270a8a506c3SXiaojuan Yang { 271a8a506c3SXiaojuan Yang .name = TYPE_LOONGARCH_MACHINE, 272a8a506c3SXiaojuan Yang .parent = TYPE_MACHINE, 273a8a506c3SXiaojuan Yang .instance_size = sizeof(LoongArchMachineState), 274a8a506c3SXiaojuan Yang .class_init = loongarch_class_init, 275a8a506c3SXiaojuan Yang } 276a8a506c3SXiaojuan Yang }; 277a8a506c3SXiaojuan Yang 278a8a506c3SXiaojuan Yang DEFINE_TYPES(loongarch_machine_types) 279