hw/loongarch: Add irq hierarchy for the system
[qemu.git] / hw / loongarch / loongson3.c
blob7a5c61e2dfb372fa873cc24afc94d20438decf2e
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3 * QEMU loongson 3a5000 develop board emulation
5 * Copyright (c) 2021 Loongson Technology Corporation Limited
6 */
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;
32 SysBusDevice *d;
33 LoongArchCPU *lacpu;
34 CPULoongArchState *env;
35 CPUState *cpu_state;
36 int cpu, pin, i;
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 * +-----+ +---------+ +-------+
49 * ^
50 * |
51 * +---------+
52 * | EIOINTC |
53 * +---------+
54 * ^ ^
55 * | |
56 * +---------+ +---------+
57 * | PCH-PIC | | PCH-MSI |
58 * +---------+ +---------+
59 * ^ ^ ^
60 * | | |
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);
69 env = &(lacpu->env);
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),
76 cpu));
77 /* extioi iocsr memory region */
78 memory_region_add_subregion(&env->system_iocsr, APIC_BASE,
79 sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi),
80 cpu));
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);
131 int i;
133 if (!cpu_model) {
134 cpu_model = LOONGARCH_CPU_TYPE_NAME("la464");
137 if (!strstr(cpu_model, "la464")) {
138 error_report("LoongArch/TCG needs cpu type la464");
139 exit(1);
142 if (ram_size < 1 * GiB) {
143 error_report("ram_size must be greater than 1G.");
144 exit(1);
147 /* Init CPUs */
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);
156 offset += 256 * MiB;
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,
167 &lams->isa_io);
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;
182 mc->is_default = 1;
183 mc->default_kernel_irqchip_split = false;
184 mc->block_default_type = IF_VIRTIO;
185 mc->default_boot_order = "c";
186 mc->no_cdrom = 1;
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)