xref: /qemu/hw/intc/loongarch_extioi_common.c (revision 8e63a7a7c2227ed014d55717c3a4de90bff426a8)
16b69f778SBibo Mao /* SPDX-License-Identifier: GPL-2.0-or-later */
26b69f778SBibo Mao /*
36b69f778SBibo Mao  * Loongson extioi interrupt controller emulation
46b69f778SBibo Mao  * Copyright (C) 2024 Loongson Technology Corporation Limited
56b69f778SBibo Mao  */
6272c467aSBibo Mao #include "qemu/osdep.h"
7e45c96b7SBibo Mao #include "qemu/error-report.h"
8272c467aSBibo Mao #include "qemu/module.h"
9272c467aSBibo Mao #include "qapi/error.h"
10272c467aSBibo Mao #include "hw/qdev-properties.h"
11272c467aSBibo Mao #include "hw/intc/loongarch_extioi_common.h"
12272c467aSBibo Mao #include "migration/vmstate.h"
13e45c96b7SBibo Mao #include "target/loongarch/cpu.h"
14e45c96b7SBibo Mao 
15*8e63a7a7SBibo Mao static ExtIOICore *loongarch_extioi_get_cpu(LoongArchExtIOICommonState *s,
16*8e63a7a7SBibo Mao                                             DeviceState *dev)
17*8e63a7a7SBibo Mao {
18*8e63a7a7SBibo Mao     CPUClass *k = CPU_GET_CLASS(dev);
19*8e63a7a7SBibo Mao     uint64_t arch_id = k->get_arch_id(CPU(dev));
20*8e63a7a7SBibo Mao     int i;
21*8e63a7a7SBibo Mao 
22*8e63a7a7SBibo Mao     for (i = 0; i < s->num_cpu; i++) {
23*8e63a7a7SBibo Mao         if (s->cpu[i].arch_id == arch_id) {
24*8e63a7a7SBibo Mao             return &s->cpu[i];
25*8e63a7a7SBibo Mao         }
26*8e63a7a7SBibo Mao     }
27*8e63a7a7SBibo Mao 
28*8e63a7a7SBibo Mao     return NULL;
29*8e63a7a7SBibo Mao }
30*8e63a7a7SBibo Mao 
31e45c96b7SBibo Mao static void loongarch_extioi_cpu_plug(HotplugHandler *hotplug_dev,
32e45c96b7SBibo Mao                                       DeviceState *dev, Error **errp)
33e45c96b7SBibo Mao {
34*8e63a7a7SBibo Mao     LoongArchExtIOICommonState *s = LOONGARCH_EXTIOI_COMMON(hotplug_dev);
35e45c96b7SBibo Mao     Object *obj = OBJECT(dev);
36*8e63a7a7SBibo Mao     ExtIOICore *core;
37*8e63a7a7SBibo Mao     int pin, index;
38e45c96b7SBibo Mao 
39e45c96b7SBibo Mao     if (!object_dynamic_cast(obj, TYPE_LOONGARCH_CPU)) {
40e45c96b7SBibo Mao         warn_report("LoongArch extioi: Invalid %s device type",
41e45c96b7SBibo Mao                                        object_get_typename(obj));
42e45c96b7SBibo Mao         return;
43e45c96b7SBibo Mao     }
44*8e63a7a7SBibo Mao 
45*8e63a7a7SBibo Mao     core = loongarch_extioi_get_cpu(s, dev);
46*8e63a7a7SBibo Mao     if (!core) {
47*8e63a7a7SBibo Mao         return;
48*8e63a7a7SBibo Mao     }
49*8e63a7a7SBibo Mao 
50*8e63a7a7SBibo Mao     core->cpu = CPU(dev);
51*8e63a7a7SBibo Mao     index = core - s->cpu;
52*8e63a7a7SBibo Mao 
53*8e63a7a7SBibo Mao     /*
54*8e63a7a7SBibo Mao      * connect extioi irq to the cpu irq
55*8e63a7a7SBibo Mao      * cpu_pin[LS3A_INTC_IP + 2 : 2] <= intc_pin[LS3A_INTC_IP : 0]
56*8e63a7a7SBibo Mao      */
57*8e63a7a7SBibo Mao     for (pin = 0; pin < LS3A_INTC_IP; pin++) {
58*8e63a7a7SBibo Mao         qdev_connect_gpio_out(DEVICE(s), index * LS3A_INTC_IP + pin,
59*8e63a7a7SBibo Mao                               qdev_get_gpio_in(dev, pin + 2));
60*8e63a7a7SBibo Mao     }
61e45c96b7SBibo Mao }
62e45c96b7SBibo Mao 
63e45c96b7SBibo Mao static void loongarch_extioi_cpu_unplug(HotplugHandler *hotplug_dev,
64e45c96b7SBibo Mao                                         DeviceState *dev, Error **errp)
65e45c96b7SBibo Mao {
66*8e63a7a7SBibo Mao     LoongArchExtIOICommonState *s = LOONGARCH_EXTIOI_COMMON(hotplug_dev);
67e45c96b7SBibo Mao     Object *obj = OBJECT(dev);
68*8e63a7a7SBibo Mao     ExtIOICore *core;
69e45c96b7SBibo Mao 
70e45c96b7SBibo Mao     if (!object_dynamic_cast(obj, TYPE_LOONGARCH_CPU)) {
71e45c96b7SBibo Mao         warn_report("LoongArch extioi: Invalid %s device type",
72e45c96b7SBibo Mao                                        object_get_typename(obj));
73e45c96b7SBibo Mao         return;
74e45c96b7SBibo Mao     }
75*8e63a7a7SBibo Mao 
76*8e63a7a7SBibo Mao     core = loongarch_extioi_get_cpu(s, dev);
77*8e63a7a7SBibo Mao     if (!core) {
78*8e63a7a7SBibo Mao         return;
79*8e63a7a7SBibo Mao     }
80*8e63a7a7SBibo Mao 
81*8e63a7a7SBibo Mao     core->cpu = NULL;
82e45c96b7SBibo Mao }
836b69f778SBibo Mao 
846b69f778SBibo Mao static void loongarch_extioi_common_realize(DeviceState *dev, Error **errp)
856b69f778SBibo Mao {
866b69f778SBibo Mao     LoongArchExtIOICommonState *s = (LoongArchExtIOICommonState *)dev;
875a3e068dSBibo Mao     MachineState *machine = MACHINE(qdev_get_machine());
885a3e068dSBibo Mao     MachineClass *mc = MACHINE_GET_CLASS(machine);
895a3e068dSBibo Mao     const CPUArchIdList *id_list;
908b4b668fSBibo Mao     int i, pin;
916b69f778SBibo Mao 
925a3e068dSBibo Mao     assert(mc->possible_cpu_arch_ids);
935a3e068dSBibo Mao     id_list = mc->possible_cpu_arch_ids(machine);
945a3e068dSBibo Mao     s->num_cpu = id_list->len;
955a3e068dSBibo Mao     s->cpu = g_new0(ExtIOICore, s->num_cpu);
965a3e068dSBibo Mao     if (s->cpu == NULL) {
975a3e068dSBibo Mao         error_setg(errp, "Memory allocation for ExtIOICore faile");
986b69f778SBibo Mao         return;
996b69f778SBibo Mao     }
1005a3e068dSBibo Mao 
1015a3e068dSBibo Mao     for (i = 0; i < s->num_cpu; i++) {
1025a3e068dSBibo Mao         s->cpu[i].arch_id = id_list->cpus[i].arch_id;
1035a3e068dSBibo Mao         s->cpu[i].cpu = CPU(id_list->cpus[i].cpu);
1048b4b668fSBibo Mao 
1058b4b668fSBibo Mao         for (pin = 0; pin < LS3A_INTC_IP; pin++) {
1068b4b668fSBibo Mao             qdev_init_gpio_out(dev, &s->cpu[i].parent_irq[pin], 1);
1078b4b668fSBibo Mao         }
1085a3e068dSBibo Mao     }
1096b69f778SBibo Mao }
1106b69f778SBibo Mao 
111ff09444aSBibo Mao static int loongarch_extioi_common_pre_save(void *opaque)
112ff09444aSBibo Mao {
113ff09444aSBibo Mao     LoongArchExtIOICommonState *s = (LoongArchExtIOICommonState *)opaque;
114ff09444aSBibo Mao     LoongArchExtIOICommonClass *lecc = LOONGARCH_EXTIOI_COMMON_GET_CLASS(s);
115ff09444aSBibo Mao 
116ff09444aSBibo Mao     if (lecc->pre_save) {
117ff09444aSBibo Mao         return lecc->pre_save(s);
118ff09444aSBibo Mao     }
119ff09444aSBibo Mao 
120ff09444aSBibo Mao     return 0;
121ff09444aSBibo Mao }
122ff09444aSBibo Mao 
1236b69f778SBibo Mao static int loongarch_extioi_common_post_load(void *opaque, int version_id)
1246b69f778SBibo Mao {
125272c467aSBibo Mao     LoongArchExtIOICommonState *s = (LoongArchExtIOICommonState *)opaque;
126272c467aSBibo Mao     LoongArchExtIOICommonClass *lecc = LOONGARCH_EXTIOI_COMMON_GET_CLASS(s);
127272c467aSBibo Mao 
128272c467aSBibo Mao     if (lecc->post_load) {
129272c467aSBibo Mao         return lecc->post_load(s, version_id);
130272c467aSBibo Mao     }
131272c467aSBibo Mao 
132272c467aSBibo Mao     return 0;
1336b69f778SBibo Mao }
1346b69f778SBibo Mao 
1356b69f778SBibo Mao static const VMStateDescription vmstate_extioi_core = {
1366b69f778SBibo Mao     .name = "extioi-core",
1376b69f778SBibo Mao     .version_id = 1,
1386b69f778SBibo Mao     .minimum_version_id = 1,
1396b69f778SBibo Mao     .fields = (const VMStateField[]) {
1406b69f778SBibo Mao         VMSTATE_UINT32_ARRAY(coreisr, ExtIOICore, EXTIOI_IRQS_GROUP_COUNT),
1416b69f778SBibo Mao         VMSTATE_END_OF_LIST()
1426b69f778SBibo Mao     }
1436b69f778SBibo Mao };
1446b69f778SBibo Mao 
1456b69f778SBibo Mao static const VMStateDescription vmstate_loongarch_extioi = {
1466b69f778SBibo Mao     .name = "loongarch.extioi",
1476b69f778SBibo Mao     .version_id = 3,
1486b69f778SBibo Mao     .minimum_version_id = 3,
149ff09444aSBibo Mao     .pre_save  = loongarch_extioi_common_pre_save,
1506b69f778SBibo Mao     .post_load = loongarch_extioi_common_post_load,
1516b69f778SBibo Mao     .fields = (const VMStateField[]) {
1526b69f778SBibo Mao         VMSTATE_UINT32_ARRAY(bounce, LoongArchExtIOICommonState,
1536b69f778SBibo Mao                              EXTIOI_IRQS_GROUP_COUNT),
1546b69f778SBibo Mao         VMSTATE_UINT32_ARRAY(nodetype, LoongArchExtIOICommonState,
1556b69f778SBibo Mao                              EXTIOI_IRQS_NODETYPE_COUNT / 2),
1566b69f778SBibo Mao         VMSTATE_UINT32_ARRAY(enable, LoongArchExtIOICommonState,
1576b69f778SBibo Mao                              EXTIOI_IRQS / 32),
1586b69f778SBibo Mao         VMSTATE_UINT32_ARRAY(isr, LoongArchExtIOICommonState,
1596b69f778SBibo Mao                              EXTIOI_IRQS / 32),
1606b69f778SBibo Mao         VMSTATE_UINT32_ARRAY(ipmap, LoongArchExtIOICommonState,
1616b69f778SBibo Mao                              EXTIOI_IRQS_IPMAP_SIZE / 4),
1626b69f778SBibo Mao         VMSTATE_UINT32_ARRAY(coremap, LoongArchExtIOICommonState,
1636b69f778SBibo Mao                              EXTIOI_IRQS / 4),
1646b69f778SBibo Mao         VMSTATE_STRUCT_VARRAY_POINTER_UINT32(cpu, LoongArchExtIOICommonState,
1656b69f778SBibo Mao                              num_cpu, vmstate_extioi_core, ExtIOICore),
1666b69f778SBibo Mao         VMSTATE_UINT32(features, LoongArchExtIOICommonState),
1676b69f778SBibo Mao         VMSTATE_UINT32(status, LoongArchExtIOICommonState),
1686b69f778SBibo Mao         VMSTATE_END_OF_LIST()
1696b69f778SBibo Mao     }
1706b69f778SBibo Mao };
1716b69f778SBibo Mao 
1726b69f778SBibo Mao static const Property extioi_properties[] = {
1736b69f778SBibo Mao     DEFINE_PROP_BIT("has-virtualization-extension", LoongArchExtIOICommonState,
1746b69f778SBibo Mao                     features, EXTIOI_HAS_VIRT_EXTENSION, 0),
1756b69f778SBibo Mao };
176272c467aSBibo Mao 
177272c467aSBibo Mao static void loongarch_extioi_common_class_init(ObjectClass *klass, void *data)
178272c467aSBibo Mao {
179272c467aSBibo Mao     DeviceClass *dc = DEVICE_CLASS(klass);
180272c467aSBibo Mao     LoongArchExtIOICommonClass *lecc = LOONGARCH_EXTIOI_COMMON_CLASS(klass);
181e45c96b7SBibo Mao     HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
182272c467aSBibo Mao 
183272c467aSBibo Mao     device_class_set_parent_realize(dc, loongarch_extioi_common_realize,
184272c467aSBibo Mao                                     &lecc->parent_realize);
185272c467aSBibo Mao     device_class_set_props(dc, extioi_properties);
186272c467aSBibo Mao     dc->vmsd = &vmstate_loongarch_extioi;
187e45c96b7SBibo Mao     hc->plug = loongarch_extioi_cpu_plug;
188e45c96b7SBibo Mao     hc->unplug = loongarch_extioi_cpu_unplug;
189272c467aSBibo Mao }
190272c467aSBibo Mao 
191272c467aSBibo Mao static const TypeInfo loongarch_extioi_common_types[] = {
192272c467aSBibo Mao     {
193272c467aSBibo Mao         .name               = TYPE_LOONGARCH_EXTIOI_COMMON,
194272c467aSBibo Mao         .parent             = TYPE_SYS_BUS_DEVICE,
195272c467aSBibo Mao         .instance_size      = sizeof(LoongArchExtIOICommonState),
196272c467aSBibo Mao         .class_size         = sizeof(LoongArchExtIOICommonClass),
197272c467aSBibo Mao         .class_init         = loongarch_extioi_common_class_init,
198e45c96b7SBibo Mao         .interfaces         = (InterfaceInfo[]) {
199e45c96b7SBibo Mao             { TYPE_HOTPLUG_HANDLER },
200e45c96b7SBibo Mao             { }
201e45c96b7SBibo Mao         },
202272c467aSBibo Mao         .abstract           = true,
203272c467aSBibo Mao     }
204272c467aSBibo Mao };
205272c467aSBibo Mao 
206272c467aSBibo Mao DEFINE_TYPES(loongarch_extioi_common_types)
207