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
loongarch_extioi_get_cpu(LoongArchExtIOICommonState * s,DeviceState * dev)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
loongarch_extioi_cpu_plug(HotplugHandler * hotplug_dev,DeviceState * dev,Error ** errp)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
loongarch_extioi_cpu_unplug(HotplugHandler * hotplug_dev,DeviceState * dev,Error ** errp)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
loongarch_extioi_common_realize(DeviceState * dev,Error ** errp)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
loongarch_extioi_common_pre_save(void * opaque)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
loongarch_extioi_common_post_load(void * opaque,int version_id)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
loongarch_extioi_common_class_init(ObjectClass * klass,void * data)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