1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 * QEMU loongson 3a5000 develop board emulation
5 * Copyright (c) 2021 Loongson Technology Corporation Limited
7 #include "qemu/osdep.h"
8 #include "qemu/units.h"
9 #include "qemu/datadir.h"
10 #include "qapi/error.h"
11 #include "hw/boards.h"
12 #include "sysemu/sysemu.h"
13 #include "sysemu/qtest.h"
14 #include "sysemu/runstate.h"
15 #include "sysemu/reset.h"
16 #include "sysemu/rtc.h"
17 #include "hw/loongarch/virt.h"
18 #include "exec/address-spaces.h"
19 #include "hw/intc/loongarch_ipi.h"
20 #include "hw/intc/loongarch_extioi.h"
21 #include "hw/intc/loongarch_pch_pic.h"
22 #include "hw/intc/loongarch_pch_msi.h"
23 #include "hw/pci-host/ls7a.h"
25 #include "target/loongarch/cpu.h"
27 static void loongarch_irq_init(LoongArchMachineState
*lams
)
29 MachineState
*ms
= MACHINE(lams
);
30 DeviceState
*pch_pic
, *pch_msi
, *cpudev
;
31 DeviceState
*ipi
, *extioi
;
34 CPULoongArchState
*env
;
38 ipi
= qdev_new(TYPE_LOONGARCH_IPI
);
39 sysbus_realize_and_unref(SYS_BUS_DEVICE(ipi
), &error_fatal
);
41 extioi
= qdev_new(TYPE_LOONGARCH_EXTIOI
);
42 sysbus_realize_and_unref(SYS_BUS_DEVICE(extioi
), &error_fatal
);
45 * The connection of interrupts:
46 * +-----+ +---------+ +-------+
47 * | IPI |--> | CPUINTC | <-- | Timer |
48 * +-----+ +---------+ +-------+
56 * +---------+ +---------+
57 * | PCH-PIC | | PCH-MSI |
58 * +---------+ +---------+
61 * +--------+ +---------+ +---------+
62 * | UARTs | | Devices | | Devices |
63 * +--------+ +---------+ +---------+
65 for (cpu
= 0; cpu
< ms
->smp
.cpus
; cpu
++) {
66 cpu_state
= qemu_get_cpu(cpu
);
67 cpudev
= DEVICE(cpu_state
);
68 lacpu
= LOONGARCH_CPU(cpu_state
);
71 /* connect ipi irq to cpu irq */
72 qdev_connect_gpio_out(ipi
, cpu
, qdev_get_gpio_in(cpudev
, IRQ_IPI
));
73 /* IPI iocsr memory region */
74 memory_region_add_subregion(&env
->system_iocsr
, SMP_IPI_MAILBOX
,
75 sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi
),
77 /* extioi iocsr memory region */
78 memory_region_add_subregion(&env
->system_iocsr
, APIC_BASE
,
79 sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi
),
84 * connect ext irq to the cpu irq
85 * cpu_pin[9:2] <= intc_pin[7:0]
87 for (cpu
= 0; cpu
< ms
->smp
.cpus
; cpu
++) {
88 cpudev
= DEVICE(qemu_get_cpu(cpu
));
89 for (pin
= 0; pin
< LS3A_INTC_IP
; pin
++) {
90 qdev_connect_gpio_out(extioi
, (cpu
* 8 + pin
),
91 qdev_get_gpio_in(cpudev
, pin
+ 2));
95 pch_pic
= qdev_new(TYPE_LOONGARCH_PCH_PIC
);
96 d
= SYS_BUS_DEVICE(pch_pic
);
97 sysbus_realize_and_unref(d
, &error_fatal
);
98 memory_region_add_subregion(get_system_memory(), LS7A_IOAPIC_REG_BASE
,
99 sysbus_mmio_get_region(d
, 0));
100 memory_region_add_subregion(get_system_memory(),
101 LS7A_IOAPIC_REG_BASE
+ PCH_PIC_ROUTE_ENTRY_OFFSET
,
102 sysbus_mmio_get_region(d
, 1));
103 memory_region_add_subregion(get_system_memory(),
104 LS7A_IOAPIC_REG_BASE
+ PCH_PIC_INT_STATUS_LO
,
105 sysbus_mmio_get_region(d
, 2));
107 /* Connect 64 pch_pic irqs to extioi */
108 for (int i
= 0; i
< PCH_PIC_IRQ_NUM
; i
++) {
109 qdev_connect_gpio_out(DEVICE(d
), i
, qdev_get_gpio_in(extioi
, i
));
112 pch_msi
= qdev_new(TYPE_LOONGARCH_PCH_MSI
);
113 d
= SYS_BUS_DEVICE(pch_msi
);
114 sysbus_realize_and_unref(d
, &error_fatal
);
115 sysbus_mmio_map(d
, 0, LS7A_PCH_MSI_ADDR_LOW
);
116 for (i
= 0; i
< PCH_MSI_IRQ_NUM
; i
++) {
117 /* Connect 192 pch_msi irqs to extioi */
118 qdev_connect_gpio_out(DEVICE(d
), i
,
119 qdev_get_gpio_in(extioi
, i
+ PCH_MSI_IRQ_START
));
123 static void loongarch_init(MachineState
*machine
)
125 const char *cpu_model
= machine
->cpu_type
;
126 ram_addr_t offset
= 0;
127 ram_addr_t ram_size
= machine
->ram_size
;
128 uint64_t highram_size
= 0;
129 MemoryRegion
*address_space_mem
= get_system_memory();
130 LoongArchMachineState
*lams
= LOONGARCH_MACHINE(machine
);
134 cpu_model
= LOONGARCH_CPU_TYPE_NAME("la464");
137 if (!strstr(cpu_model
, "la464")) {
138 error_report("LoongArch/TCG needs cpu type la464");
142 if (ram_size
< 1 * GiB
) {
143 error_report("ram_size must be greater than 1G.");
148 for (i
= 0; i
< machine
->smp
.cpus
; i
++) {
149 cpu_create(machine
->cpu_type
);
152 /* Add memory region */
153 memory_region_init_alias(&lams
->lowmem
, NULL
, "loongarch.lowram",
154 machine
->ram
, 0, 256 * MiB
);
155 memory_region_add_subregion(address_space_mem
, offset
, &lams
->lowmem
);
158 highram_size
= ram_size
- 256 * MiB
;
159 memory_region_init_alias(&lams
->highmem
, NULL
, "loongarch.highmem",
160 machine
->ram
, offset
, highram_size
);
161 memory_region_add_subregion(address_space_mem
, 0x90000000, &lams
->highmem
);
163 /* Add isa io region */
164 memory_region_init_alias(&lams
->isa_io
, NULL
, "isa-io",
165 get_system_io(), 0, LOONGARCH_ISA_IO_SIZE
);
166 memory_region_add_subregion(address_space_mem
, LOONGARCH_ISA_IO_BASE
,
168 /* Initialize the IO interrupt subsystem */
169 loongarch_irq_init(lams
);
172 static void loongarch_class_init(ObjectClass
*oc
, void *data
)
174 MachineClass
*mc
= MACHINE_CLASS(oc
);
176 mc
->desc
= "Loongson-3A5000 LS7A1000 machine";
177 mc
->init
= loongarch_init
;
178 mc
->default_ram_size
= 1 * GiB
;
179 mc
->default_cpu_type
= LOONGARCH_CPU_TYPE_NAME("la464");
180 mc
->default_ram_id
= "loongarch.ram";
181 mc
->max_cpus
= LOONGARCH_MAX_VCPUS
;
183 mc
->default_kernel_irqchip_split
= false;
184 mc
->block_default_type
= IF_VIRTIO
;
185 mc
->default_boot_order
= "c";
189 static const TypeInfo loongarch_machine_types
[] = {
191 .name
= TYPE_LOONGARCH_MACHINE
,
192 .parent
= TYPE_MACHINE
,
193 .instance_size
= sizeof(LoongArchMachineState
),
194 .class_init
= loongarch_class_init
,
198 DEFINE_TYPES(loongarch_machine_types
)