xref: /qemu/hw/intc/loongarch_extioi_common.c (revision c5e2c4042e3c50b96cc5eaa9683325c5a96913b0)
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