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 "hw/char/serial.h"
13 #include "sysemu/sysemu.h"
14 #include "sysemu/qtest.h"
15 #include "sysemu/runstate.h"
16 #include "sysemu/reset.h"
17 #include "sysemu/rtc.h"
18 #include "hw/loongarch/virt.h"
19 #include "exec/address-spaces.h"
22 #include "hw/loader.h"
24 #include "hw/intc/loongarch_ipi.h"
25 #include "hw/intc/loongarch_extioi.h"
26 #include "hw/intc/loongarch_pch_pic.h"
27 #include "hw/intc/loongarch_pch_msi.h"
28 #include "hw/pci-host/ls7a.h"
29 #include "hw/pci-host/gpex.h"
30 #include "hw/misc/unimp.h"
31 #include "hw/loongarch/fw_cfg.h"
32 #include "target/loongarch/cpu.h"
34 #define PM_BASE 0x10080000
45 static struct memmap_entry
*memmap_table
;
46 static unsigned memmap_entries
;
48 static void memmap_add_entry(uint64_t address
, uint64_t length
, uint32_t type
)
50 /* Ensure there are no duplicate entries. */
51 for (unsigned i
= 0; i
< memmap_entries
; i
++) {
52 assert(memmap_table
[i
].address
!= address
);
55 memmap_table
= g_renew(struct memmap_entry
, memmap_table
,
57 memmap_table
[memmap_entries
].address
= cpu_to_le64(address
);
58 memmap_table
[memmap_entries
].length
= cpu_to_le64(length
);
59 memmap_table
[memmap_entries
].type
= cpu_to_le32(type
);
60 memmap_table
[memmap_entries
].reserved
= 0;
66 * This is a placeholder for missing ACPI,
67 * and will eventually be replaced.
69 static uint64_t loongarch_virt_pm_read(void *opaque
, hwaddr addr
, unsigned size
)
74 static void loongarch_virt_pm_write(void *opaque
, hwaddr addr
,
75 uint64_t val
, unsigned size
)
77 if (addr
!= PM_CTRL
) {
83 qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET
);
86 qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN
);
93 static const MemoryRegionOps loongarch_virt_pm_ops
= {
94 .read
= loongarch_virt_pm_read
,
95 .write
= loongarch_virt_pm_write
,
96 .endianness
= DEVICE_NATIVE_ENDIAN
,
103 static struct _loaderparams
{
105 const char *kernel_filename
;
108 static uint64_t cpu_loongarch_virt_to_phys(void *opaque
, uint64_t addr
)
110 return addr
& 0x1fffffffll
;
113 static int64_t load_kernel_info(void)
115 uint64_t kernel_entry
, kernel_low
, kernel_high
;
118 kernel_size
= load_elf(loaderparams
.kernel_filename
, NULL
,
119 cpu_loongarch_virt_to_phys
, NULL
,
120 &kernel_entry
, &kernel_low
,
121 &kernel_high
, NULL
, 0,
124 if (kernel_size
< 0) {
125 error_report("could not load kernel '%s': %s",
126 loaderparams
.kernel_filename
,
127 load_elf_strerror(kernel_size
));
133 static void loongarch_devices_init(DeviceState
*pch_pic
)
135 DeviceState
*gpex_dev
;
138 MemoryRegion
*ecam_alias
, *ecam_reg
, *pio_alias
, *pio_reg
;
139 MemoryRegion
*mmio_alias
, *mmio_reg
, *pm_mem
;
142 gpex_dev
= qdev_new(TYPE_GPEX_HOST
);
143 d
= SYS_BUS_DEVICE(gpex_dev
);
144 sysbus_realize_and_unref(d
, &error_fatal
);
145 pci_bus
= PCI_HOST_BRIDGE(gpex_dev
)->bus
;
147 /* Map only part size_ecam bytes of ECAM space */
148 ecam_alias
= g_new0(MemoryRegion
, 1);
149 ecam_reg
= sysbus_mmio_get_region(d
, 0);
150 memory_region_init_alias(ecam_alias
, OBJECT(gpex_dev
), "pcie-ecam",
151 ecam_reg
, 0, LS_PCIECFG_SIZE
);
152 memory_region_add_subregion(get_system_memory(), LS_PCIECFG_BASE
,
155 /* Map PCI mem space */
156 mmio_alias
= g_new0(MemoryRegion
, 1);
157 mmio_reg
= sysbus_mmio_get_region(d
, 1);
158 memory_region_init_alias(mmio_alias
, OBJECT(gpex_dev
), "pcie-mmio",
159 mmio_reg
, LS7A_PCI_MEM_BASE
, LS7A_PCI_MEM_SIZE
);
160 memory_region_add_subregion(get_system_memory(), LS7A_PCI_MEM_BASE
,
163 /* Map PCI IO port space. */
164 pio_alias
= g_new0(MemoryRegion
, 1);
165 pio_reg
= sysbus_mmio_get_region(d
, 2);
166 memory_region_init_alias(pio_alias
, OBJECT(gpex_dev
), "pcie-io", pio_reg
,
167 LS7A_PCI_IO_OFFSET
, LS7A_PCI_IO_SIZE
);
168 memory_region_add_subregion(get_system_memory(), LS7A_PCI_IO_BASE
,
171 for (i
= 0; i
< GPEX_NUM_IRQS
; i
++) {
172 sysbus_connect_irq(d
, i
,
173 qdev_get_gpio_in(pch_pic
, 16 + i
));
174 gpex_set_irq_num(GPEX_HOST(gpex_dev
), i
, 16 + i
);
177 serial_mm_init(get_system_memory(), LS7A_UART_BASE
, 0,
178 qdev_get_gpio_in(pch_pic
,
179 LS7A_UART_IRQ
- PCH_PIC_IRQ_OFFSET
),
180 115200, serial_hd(0), DEVICE_LITTLE_ENDIAN
);
183 for (i
= 0; i
< nb_nics
; i
++) {
184 NICInfo
*nd
= &nd_table
[i
];
187 nd
->model
= g_strdup("virtio");
190 pci_nic_init_nofail(nd
, pci_bus
, nd
->model
, NULL
);
194 pci_vga_init(pci_bus
);
197 * There are some invalid guest memory access.
198 * Create some unimplemented devices to emulate this.
200 create_unimplemented_device("pci-dma-cfg", 0x1001041c, 0x4);
201 sysbus_create_simple("ls7a_rtc", LS7A_RTC_REG_BASE
,
202 qdev_get_gpio_in(pch_pic
,
203 LS7A_RTC_IRQ
- PCH_PIC_IRQ_OFFSET
));
205 pm_mem
= g_new(MemoryRegion
, 1);
206 memory_region_init_io(pm_mem
, NULL
, &loongarch_virt_pm_ops
,
207 NULL
, "loongarch_virt_pm", PM_SIZE
);
208 memory_region_add_subregion(get_system_memory(), PM_BASE
, pm_mem
);
211 static void loongarch_irq_init(LoongArchMachineState
*lams
)
213 MachineState
*ms
= MACHINE(lams
);
214 DeviceState
*pch_pic
, *pch_msi
, *cpudev
;
215 DeviceState
*ipi
, *extioi
;
218 CPULoongArchState
*env
;
222 ipi
= qdev_new(TYPE_LOONGARCH_IPI
);
223 sysbus_realize_and_unref(SYS_BUS_DEVICE(ipi
), &error_fatal
);
225 extioi
= qdev_new(TYPE_LOONGARCH_EXTIOI
);
226 sysbus_realize_and_unref(SYS_BUS_DEVICE(extioi
), &error_fatal
);
229 * The connection of interrupts:
230 * +-----+ +---------+ +-------+
231 * | IPI |--> | CPUINTC | <-- | Timer |
232 * +-----+ +---------+ +-------+
240 * +---------+ +---------+
241 * | PCH-PIC | | PCH-MSI |
242 * +---------+ +---------+
245 * +--------+ +---------+ +---------+
246 * | UARTs | | Devices | | Devices |
247 * +--------+ +---------+ +---------+
249 for (cpu
= 0; cpu
< ms
->smp
.cpus
; cpu
++) {
250 cpu_state
= qemu_get_cpu(cpu
);
251 cpudev
= DEVICE(cpu_state
);
252 lacpu
= LOONGARCH_CPU(cpu_state
);
255 /* connect ipi irq to cpu irq */
256 qdev_connect_gpio_out(ipi
, cpu
, qdev_get_gpio_in(cpudev
, IRQ_IPI
));
257 /* IPI iocsr memory region */
258 memory_region_add_subregion(&env
->system_iocsr
, SMP_IPI_MAILBOX
,
259 sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi
),
261 memory_region_add_subregion(&env
->system_iocsr
, MAIL_SEND_ADDR
,
262 sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi
),
264 /* extioi iocsr memory region */
265 memory_region_add_subregion(&env
->system_iocsr
, APIC_BASE
,
266 sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi
),
271 * connect ext irq to the cpu irq
272 * cpu_pin[9:2] <= intc_pin[7:0]
274 for (cpu
= 0; cpu
< ms
->smp
.cpus
; cpu
++) {
275 cpudev
= DEVICE(qemu_get_cpu(cpu
));
276 for (pin
= 0; pin
< LS3A_INTC_IP
; pin
++) {
277 qdev_connect_gpio_out(extioi
, (cpu
* 8 + pin
),
278 qdev_get_gpio_in(cpudev
, pin
+ 2));
282 pch_pic
= qdev_new(TYPE_LOONGARCH_PCH_PIC
);
283 d
= SYS_BUS_DEVICE(pch_pic
);
284 sysbus_realize_and_unref(d
, &error_fatal
);
285 memory_region_add_subregion(get_system_memory(), LS7A_IOAPIC_REG_BASE
,
286 sysbus_mmio_get_region(d
, 0));
287 memory_region_add_subregion(get_system_memory(),
288 LS7A_IOAPIC_REG_BASE
+ PCH_PIC_ROUTE_ENTRY_OFFSET
,
289 sysbus_mmio_get_region(d
, 1));
290 memory_region_add_subregion(get_system_memory(),
291 LS7A_IOAPIC_REG_BASE
+ PCH_PIC_INT_STATUS_LO
,
292 sysbus_mmio_get_region(d
, 2));
294 /* Connect 64 pch_pic irqs to extioi */
295 for (int i
= 0; i
< PCH_PIC_IRQ_NUM
; i
++) {
296 qdev_connect_gpio_out(DEVICE(d
), i
, qdev_get_gpio_in(extioi
, i
));
299 pch_msi
= qdev_new(TYPE_LOONGARCH_PCH_MSI
);
300 qdev_prop_set_uint32(pch_msi
, "msi_irq_base", PCH_MSI_IRQ_START
);
301 d
= SYS_BUS_DEVICE(pch_msi
);
302 sysbus_realize_and_unref(d
, &error_fatal
);
303 sysbus_mmio_map(d
, 0, LS7A_PCH_MSI_ADDR_LOW
);
304 for (i
= 0; i
< PCH_MSI_IRQ_NUM
; i
++) {
305 /* Connect 192 pch_msi irqs to extioi */
306 qdev_connect_gpio_out(DEVICE(d
), i
,
307 qdev_get_gpio_in(extioi
, i
+ PCH_MSI_IRQ_START
));
310 loongarch_devices_init(pch_pic
);
313 static void reset_load_elf(void *opaque
)
315 LoongArchCPU
*cpu
= opaque
;
316 CPULoongArchState
*env
= &cpu
->env
;
320 cpu_set_pc(CPU(cpu
), env
->elf_address
);
324 static void loongarch_init(MachineState
*machine
)
326 const char *cpu_model
= machine
->cpu_type
;
327 const char *kernel_filename
= machine
->kernel_filename
;
328 ram_addr_t offset
= 0;
329 ram_addr_t ram_size
= machine
->ram_size
;
330 uint64_t highram_size
= 0;
331 MemoryRegion
*address_space_mem
= get_system_memory();
332 LoongArchMachineState
*lams
= LOONGARCH_MACHINE(machine
);
335 int64_t kernel_addr
= 0;
338 cpu_model
= LOONGARCH_CPU_TYPE_NAME("la464");
341 if (!strstr(cpu_model
, "la464")) {
342 error_report("LoongArch/TCG needs cpu type la464");
346 if (ram_size
< 1 * GiB
) {
347 error_report("ram_size must be greater than 1G.");
352 for (i
= 0; i
< machine
->smp
.cpus
; i
++) {
353 cpu_create(machine
->cpu_type
);
356 /* Add memory region */
357 memory_region_init_alias(&lams
->lowmem
, NULL
, "loongarch.lowram",
358 machine
->ram
, 0, 256 * MiB
);
359 memory_region_add_subregion(address_space_mem
, offset
, &lams
->lowmem
);
361 memmap_add_entry(0, 256 * MiB
, 1);
362 highram_size
= ram_size
- 256 * MiB
;
363 memory_region_init_alias(&lams
->highmem
, NULL
, "loongarch.highmem",
364 machine
->ram
, offset
, highram_size
);
365 memory_region_add_subregion(address_space_mem
, 0x90000000, &lams
->highmem
);
366 memmap_add_entry(0x90000000, highram_size
, 1);
367 /* Add isa io region */
368 memory_region_init_alias(&lams
->isa_io
, NULL
, "isa-io",
369 get_system_io(), 0, LOONGARCH_ISA_IO_SIZE
);
370 memory_region_add_subregion(address_space_mem
, LOONGARCH_ISA_IO_BASE
,
373 lams
->fw_cfg
= loongarch_fw_cfg_init(ram_size
, machine
);
374 rom_set_fw(lams
->fw_cfg
);
376 if (lams
->fw_cfg
!= NULL
) {
377 fw_cfg_add_file(lams
->fw_cfg
, "etc/memmap",
379 sizeof(struct memmap_entry
) * (memmap_entries
));
382 if (kernel_filename
) {
383 loaderparams
.ram_size
= ram_size
;
384 loaderparams
.kernel_filename
= kernel_filename
;
385 kernel_addr
= load_kernel_info();
386 if (!machine
->firmware
) {
387 for (i
= 0; i
< machine
->smp
.cpus
; i
++) {
388 lacpu
= LOONGARCH_CPU(qemu_get_cpu(i
));
389 lacpu
->env
.load_elf
= true;
390 lacpu
->env
.elf_address
= kernel_addr
;
391 qemu_register_reset(reset_load_elf
, lacpu
);
395 /* Initialize the IO interrupt subsystem */
396 loongarch_irq_init(lams
);
399 static void loongarch_class_init(ObjectClass
*oc
, void *data
)
401 MachineClass
*mc
= MACHINE_CLASS(oc
);
403 mc
->desc
= "Loongson-3A5000 LS7A1000 machine";
404 mc
->init
= loongarch_init
;
405 mc
->default_ram_size
= 1 * GiB
;
406 mc
->default_cpu_type
= LOONGARCH_CPU_TYPE_NAME("la464");
407 mc
->default_ram_id
= "loongarch.ram";
408 mc
->max_cpus
= LOONGARCH_MAX_VCPUS
;
410 mc
->default_kernel_irqchip_split
= false;
411 mc
->block_default_type
= IF_VIRTIO
;
412 mc
->default_boot_order
= "c";
416 static const TypeInfo loongarch_machine_types
[] = {
418 .name
= TYPE_LOONGARCH_MACHINE
,
419 .parent
= TYPE_MACHINE
,
420 .instance_size
= sizeof(LoongArchMachineState
),
421 .class_init
= loongarch_class_init
,
425 DEFINE_TYPES(loongarch_machine_types
)