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)158e63a7a7SBibo Mao static ExtIOICore *loongarch_extioi_get_cpu(LoongArchExtIOICommonState *s,
168e63a7a7SBibo Mao DeviceState *dev)
178e63a7a7SBibo Mao {
188e63a7a7SBibo Mao CPUClass *k = CPU_GET_CLASS(dev);
198e63a7a7SBibo Mao uint64_t arch_id = k->get_arch_id(CPU(dev));
208e63a7a7SBibo Mao int i;
218e63a7a7SBibo Mao
228e63a7a7SBibo Mao for (i = 0; i < s->num_cpu; i++) {
238e63a7a7SBibo Mao if (s->cpu[i].arch_id == arch_id) {
248e63a7a7SBibo Mao return &s->cpu[i];
258e63a7a7SBibo Mao }
268e63a7a7SBibo Mao }
278e63a7a7SBibo Mao
288e63a7a7SBibo Mao return NULL;
298e63a7a7SBibo Mao }
308e63a7a7SBibo 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 {
348e63a7a7SBibo Mao LoongArchExtIOICommonState *s = LOONGARCH_EXTIOI_COMMON(hotplug_dev);
35e45c96b7SBibo Mao Object *obj = OBJECT(dev);
368e63a7a7SBibo Mao ExtIOICore *core;
378e63a7a7SBibo 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 }
448e63a7a7SBibo Mao
458e63a7a7SBibo Mao core = loongarch_extioi_get_cpu(s, dev);
468e63a7a7SBibo Mao if (!core) {
478e63a7a7SBibo Mao return;
488e63a7a7SBibo Mao }
498e63a7a7SBibo Mao
508e63a7a7SBibo Mao core->cpu = CPU(dev);
518e63a7a7SBibo Mao index = core - s->cpu;
528e63a7a7SBibo Mao
538e63a7a7SBibo Mao /*
548e63a7a7SBibo Mao * connect extioi irq to the cpu irq
558e63a7a7SBibo Mao * cpu_pin[LS3A_INTC_IP + 2 : 2] <= intc_pin[LS3A_INTC_IP : 0]
568e63a7a7SBibo Mao */
578e63a7a7SBibo Mao for (pin = 0; pin < LS3A_INTC_IP; pin++) {
588e63a7a7SBibo Mao qdev_connect_gpio_out(DEVICE(s), index * LS3A_INTC_IP + pin,
598e63a7a7SBibo Mao qdev_get_gpio_in(dev, pin + 2));
608e63a7a7SBibo 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 {
668e63a7a7SBibo Mao LoongArchExtIOICommonState *s = LOONGARCH_EXTIOI_COMMON(hotplug_dev);
67e45c96b7SBibo Mao Object *obj = OBJECT(dev);
688e63a7a7SBibo 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 }
758e63a7a7SBibo Mao
768e63a7a7SBibo Mao core = loongarch_extioi_get_cpu(s, dev);
778e63a7a7SBibo Mao if (!core) {
788e63a7a7SBibo Mao return;
798e63a7a7SBibo Mao }
808e63a7a7SBibo Mao
818e63a7a7SBibo 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_reset_hold(Object * obj,ResetType type)111*86e4a647SBibo Mao static void loongarch_extioi_common_reset_hold(Object *obj, ResetType type)
112*86e4a647SBibo Mao {
113*86e4a647SBibo Mao LoongArchExtIOICommonClass *lecc = LOONGARCH_EXTIOI_COMMON_GET_CLASS(obj);
114*86e4a647SBibo Mao LoongArchExtIOICommonState *s = LOONGARCH_EXTIOI_COMMON(obj);
115*86e4a647SBibo Mao ExtIOICore *core;
116*86e4a647SBibo Mao int i;
117*86e4a647SBibo Mao
118*86e4a647SBibo Mao if (lecc->parent_phases.hold) {
119*86e4a647SBibo Mao lecc->parent_phases.hold(obj, type);
120*86e4a647SBibo Mao }
121*86e4a647SBibo Mao
122*86e4a647SBibo Mao /* Clear HW registers for the board */
123*86e4a647SBibo Mao memset(s->nodetype, 0, sizeof(s->nodetype));
124*86e4a647SBibo Mao memset(s->bounce, 0, sizeof(s->bounce));
125*86e4a647SBibo Mao memset(s->isr, 0, sizeof(s->isr));
126*86e4a647SBibo Mao memset(s->enable, 0, sizeof(s->enable));
127*86e4a647SBibo Mao memset(s->ipmap, 0, sizeof(s->ipmap));
128*86e4a647SBibo Mao memset(s->coremap, 0, sizeof(s->coremap));
129*86e4a647SBibo Mao memset(s->sw_pending, 0, sizeof(s->sw_pending));
130*86e4a647SBibo Mao memset(s->sw_ipmap, 0, sizeof(s->sw_ipmap));
131*86e4a647SBibo Mao memset(s->sw_coremap, 0, sizeof(s->sw_coremap));
132*86e4a647SBibo Mao
133*86e4a647SBibo Mao for (i = 0; i < s->num_cpu; i++) {
134*86e4a647SBibo Mao core = s->cpu + i;
135*86e4a647SBibo Mao /* EXTIOI with targeted CPU available however not present */
136*86e4a647SBibo Mao if (!core->cpu) {
137*86e4a647SBibo Mao continue;
138*86e4a647SBibo Mao }
139*86e4a647SBibo Mao
140*86e4a647SBibo Mao /* Clear HW registers for CPUs */
141*86e4a647SBibo Mao memset(core->coreisr, 0, sizeof(core->coreisr));
142*86e4a647SBibo Mao memset(core->sw_isr, 0, sizeof(core->sw_isr));
143*86e4a647SBibo Mao }
144*86e4a647SBibo Mao
145*86e4a647SBibo Mao s->status = 0;
146*86e4a647SBibo Mao }
147*86e4a647SBibo Mao
loongarch_extioi_common_pre_save(void * opaque)148ff09444aSBibo Mao static int loongarch_extioi_common_pre_save(void *opaque)
149ff09444aSBibo Mao {
150ff09444aSBibo Mao LoongArchExtIOICommonState *s = (LoongArchExtIOICommonState *)opaque;
151ff09444aSBibo Mao LoongArchExtIOICommonClass *lecc = LOONGARCH_EXTIOI_COMMON_GET_CLASS(s);
152ff09444aSBibo Mao
153ff09444aSBibo Mao if (lecc->pre_save) {
154ff09444aSBibo Mao return lecc->pre_save(s);
155ff09444aSBibo Mao }
156ff09444aSBibo Mao
157ff09444aSBibo Mao return 0;
158ff09444aSBibo Mao }
159ff09444aSBibo Mao
loongarch_extioi_common_post_load(void * opaque,int version_id)1606b69f778SBibo Mao static int loongarch_extioi_common_post_load(void *opaque, int version_id)
1616b69f778SBibo Mao {
162272c467aSBibo Mao LoongArchExtIOICommonState *s = (LoongArchExtIOICommonState *)opaque;
163272c467aSBibo Mao LoongArchExtIOICommonClass *lecc = LOONGARCH_EXTIOI_COMMON_GET_CLASS(s);
164272c467aSBibo Mao
165272c467aSBibo Mao if (lecc->post_load) {
166272c467aSBibo Mao return lecc->post_load(s, version_id);
167272c467aSBibo Mao }
168272c467aSBibo Mao
169272c467aSBibo Mao return 0;
1706b69f778SBibo Mao }
1716b69f778SBibo Mao
1726b69f778SBibo Mao static const VMStateDescription vmstate_extioi_core = {
1736b69f778SBibo Mao .name = "extioi-core",
1746b69f778SBibo Mao .version_id = 1,
1756b69f778SBibo Mao .minimum_version_id = 1,
1766b69f778SBibo Mao .fields = (const VMStateField[]) {
1776b69f778SBibo Mao VMSTATE_UINT32_ARRAY(coreisr, ExtIOICore, EXTIOI_IRQS_GROUP_COUNT),
1786b69f778SBibo Mao VMSTATE_END_OF_LIST()
1796b69f778SBibo Mao }
1806b69f778SBibo Mao };
1816b69f778SBibo Mao
1826b69f778SBibo Mao static const VMStateDescription vmstate_loongarch_extioi = {
1836b69f778SBibo Mao .name = "loongarch.extioi",
1846b69f778SBibo Mao .version_id = 3,
1856b69f778SBibo Mao .minimum_version_id = 3,
186ff09444aSBibo Mao .pre_save = loongarch_extioi_common_pre_save,
1876b69f778SBibo Mao .post_load = loongarch_extioi_common_post_load,
1886b69f778SBibo Mao .fields = (const VMStateField[]) {
1896b69f778SBibo Mao VMSTATE_UINT32_ARRAY(bounce, LoongArchExtIOICommonState,
1906b69f778SBibo Mao EXTIOI_IRQS_GROUP_COUNT),
1916b69f778SBibo Mao VMSTATE_UINT32_ARRAY(nodetype, LoongArchExtIOICommonState,
1926b69f778SBibo Mao EXTIOI_IRQS_NODETYPE_COUNT / 2),
1936b69f778SBibo Mao VMSTATE_UINT32_ARRAY(enable, LoongArchExtIOICommonState,
1946b69f778SBibo Mao EXTIOI_IRQS / 32),
1956b69f778SBibo Mao VMSTATE_UINT32_ARRAY(isr, LoongArchExtIOICommonState,
1966b69f778SBibo Mao EXTIOI_IRQS / 32),
1976b69f778SBibo Mao VMSTATE_UINT32_ARRAY(ipmap, LoongArchExtIOICommonState,
1986b69f778SBibo Mao EXTIOI_IRQS_IPMAP_SIZE / 4),
1996b69f778SBibo Mao VMSTATE_UINT32_ARRAY(coremap, LoongArchExtIOICommonState,
2006b69f778SBibo Mao EXTIOI_IRQS / 4),
2016b69f778SBibo Mao VMSTATE_STRUCT_VARRAY_POINTER_UINT32(cpu, LoongArchExtIOICommonState,
2026b69f778SBibo Mao num_cpu, vmstate_extioi_core, ExtIOICore),
2036b69f778SBibo Mao VMSTATE_UINT32(features, LoongArchExtIOICommonState),
2046b69f778SBibo Mao VMSTATE_UINT32(status, LoongArchExtIOICommonState),
2056b69f778SBibo Mao VMSTATE_END_OF_LIST()
2066b69f778SBibo Mao }
2076b69f778SBibo Mao };
2086b69f778SBibo Mao
2096b69f778SBibo Mao static const Property extioi_properties[] = {
2106b69f778SBibo Mao DEFINE_PROP_BIT("has-virtualization-extension", LoongArchExtIOICommonState,
2116b69f778SBibo Mao features, EXTIOI_HAS_VIRT_EXTENSION, 0),
2126b69f778SBibo Mao };
213272c467aSBibo Mao
loongarch_extioi_common_class_init(ObjectClass * klass,const void * data)21412d1a768SPhilippe Mathieu-Daudé static void loongarch_extioi_common_class_init(ObjectClass *klass,
21512d1a768SPhilippe Mathieu-Daudé const void *data)
216272c467aSBibo Mao {
217272c467aSBibo Mao DeviceClass *dc = DEVICE_CLASS(klass);
218272c467aSBibo Mao LoongArchExtIOICommonClass *lecc = LOONGARCH_EXTIOI_COMMON_CLASS(klass);
219e45c96b7SBibo Mao HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
220*86e4a647SBibo Mao ResettableClass *rc = RESETTABLE_CLASS(klass);
221272c467aSBibo Mao
222272c467aSBibo Mao device_class_set_parent_realize(dc, loongarch_extioi_common_realize,
223272c467aSBibo Mao &lecc->parent_realize);
224*86e4a647SBibo Mao resettable_class_set_parent_phases(rc, NULL,
225*86e4a647SBibo Mao loongarch_extioi_common_reset_hold,
226*86e4a647SBibo Mao NULL, &lecc->parent_phases);
227272c467aSBibo Mao device_class_set_props(dc, extioi_properties);
228272c467aSBibo Mao dc->vmsd = &vmstate_loongarch_extioi;
229e45c96b7SBibo Mao hc->plug = loongarch_extioi_cpu_plug;
230e45c96b7SBibo Mao hc->unplug = loongarch_extioi_cpu_unplug;
231272c467aSBibo Mao }
232272c467aSBibo Mao
233272c467aSBibo Mao static const TypeInfo loongarch_extioi_common_types[] = {
234272c467aSBibo Mao {
235272c467aSBibo Mao .name = TYPE_LOONGARCH_EXTIOI_COMMON,
236272c467aSBibo Mao .parent = TYPE_SYS_BUS_DEVICE,
237272c467aSBibo Mao .instance_size = sizeof(LoongArchExtIOICommonState),
238272c467aSBibo Mao .class_size = sizeof(LoongArchExtIOICommonClass),
239272c467aSBibo Mao .class_init = loongarch_extioi_common_class_init,
2402cd09e47SPhilippe Mathieu-Daudé .interfaces = (const InterfaceInfo[]) {
241e45c96b7SBibo Mao { TYPE_HOTPLUG_HANDLER },
242e45c96b7SBibo Mao { }
243e45c96b7SBibo Mao },
244272c467aSBibo Mao .abstract = true,
245272c467aSBibo Mao }
246272c467aSBibo Mao };
247272c467aSBibo Mao
248272c467aSBibo Mao DEFINE_TYPES(loongarch_extioi_common_types)
249