xref: /openbmc/qemu/hw/intc/goldfish_pic.c (revision 7d87775f)
1 /*
2  * SPDX-License-Identifier: GPL-2.0-or-later
3  *
4  * Goldfish PIC
5  *
6  * (c) 2020 Laurent Vivier <laurent@vivier.eu>
7  *
8  */
9 
10 #include "qemu/osdep.h"
11 #include "hw/irq.h"
12 #include "hw/qdev-properties.h"
13 #include "hw/sysbus.h"
14 #include "migration/vmstate.h"
15 #include "qemu/log.h"
16 #include "trace.h"
17 #include "hw/intc/intc.h"
18 #include "hw/intc/goldfish_pic.h"
19 
20 /* registers */
21 
22 enum {
23     REG_STATUS          = 0x00,
24     REG_IRQ_PENDING     = 0x04,
25     REG_IRQ_DISABLE_ALL = 0x08,
26     REG_DISABLE         = 0x0c,
27     REG_ENABLE          = 0x10,
28 };
29 
30 static bool goldfish_pic_get_statistics(InterruptStatsProvider *obj,
31                                         uint64_t **irq_counts,
32                                         unsigned int *nb_irqs)
33 {
34     GoldfishPICState *s = GOLDFISH_PIC(obj);
35 
36     *irq_counts = s->stats_irq_count;
37     *nb_irqs = ARRAY_SIZE(s->stats_irq_count);
38     return true;
39 }
40 
41 static void goldfish_pic_print_info(InterruptStatsProvider *obj, GString *buf)
42 {
43     GoldfishPICState *s = GOLDFISH_PIC(obj);
44     g_string_append_printf(buf,
45                            "goldfish-pic.%d: pending=0x%08x enabled=0x%08x\n",
46                            s->idx, s->pending, s->enabled);
47 }
48 
49 static void goldfish_pic_update(GoldfishPICState *s)
50 {
51     if (s->pending & s->enabled) {
52         qemu_irq_raise(s->irq);
53     } else {
54         qemu_irq_lower(s->irq);
55     }
56 }
57 
58 static void goldfish_irq_request(void *opaque, int irq, int level)
59 {
60     GoldfishPICState *s = opaque;
61 
62     trace_goldfish_irq_request(s, s->idx, irq, level);
63 
64     if (level) {
65         s->pending |= 1 << irq;
66         s->stats_irq_count[irq]++;
67     } else {
68         s->pending &= ~(1 << irq);
69     }
70     goldfish_pic_update(s);
71 }
72 
73 static uint64_t goldfish_pic_read(void *opaque, hwaddr addr,
74                                   unsigned size)
75 {
76     GoldfishPICState *s = opaque;
77     uint64_t value = 0;
78 
79     switch (addr) {
80     case REG_STATUS:
81         /* The number of pending interrupts (0 to 32) */
82         value = ctpop32(s->pending & s->enabled);
83         break;
84     case REG_IRQ_PENDING:
85         /* The pending interrupt mask */
86         value = s->pending & s->enabled;
87         break;
88     default:
89         qemu_log_mask(LOG_UNIMP,
90                       "%s: unimplemented register read 0x%02"HWADDR_PRIx"\n",
91                       __func__, addr);
92         break;
93     }
94 
95     trace_goldfish_pic_read(s, s->idx, addr, size, value);
96 
97     return value;
98 }
99 
100 static void goldfish_pic_write(void *opaque, hwaddr addr,
101                                uint64_t value, unsigned size)
102 {
103     GoldfishPICState *s = opaque;
104 
105     trace_goldfish_pic_write(s, s->idx, addr, size, value);
106 
107     switch (addr) {
108     case REG_IRQ_DISABLE_ALL:
109         s->enabled = 0;
110         s->pending = 0;
111         break;
112     case REG_DISABLE:
113         s->enabled &= ~value;
114         break;
115     case REG_ENABLE:
116         s->enabled |= value;
117         break;
118     default:
119         qemu_log_mask(LOG_UNIMP,
120                       "%s: unimplemented register write 0x%02"HWADDR_PRIx"\n",
121                       __func__, addr);
122         break;
123     }
124     goldfish_pic_update(s);
125 }
126 
127 static const MemoryRegionOps goldfish_pic_ops = {
128     .read = goldfish_pic_read,
129     .write = goldfish_pic_write,
130     .endianness = DEVICE_NATIVE_ENDIAN,
131     .valid.max_access_size = 4,
132     .impl.min_access_size = 4,
133     .impl.max_access_size = 4,
134 };
135 
136 static void goldfish_pic_reset(DeviceState *dev)
137 {
138     GoldfishPICState *s = GOLDFISH_PIC(dev);
139     int i;
140 
141     trace_goldfish_pic_reset(s, s->idx);
142     s->pending = 0;
143     s->enabled = 0;
144 
145     for (i = 0; i < ARRAY_SIZE(s->stats_irq_count); i++) {
146         s->stats_irq_count[i] = 0;
147     }
148 }
149 
150 static void goldfish_pic_realize(DeviceState *dev, Error **errp)
151 {
152     GoldfishPICState *s = GOLDFISH_PIC(dev);
153 
154     trace_goldfish_pic_realize(s, s->idx);
155 
156     memory_region_init_io(&s->iomem, OBJECT(s), &goldfish_pic_ops, s,
157                           "goldfish_pic", 0x24);
158 }
159 
160 static const VMStateDescription vmstate_goldfish_pic = {
161     .name = "goldfish_pic",
162     .version_id = 1,
163     .minimum_version_id = 1,
164     .fields = (const VMStateField[]) {
165         VMSTATE_UINT32(pending, GoldfishPICState),
166         VMSTATE_UINT32(enabled, GoldfishPICState),
167         VMSTATE_END_OF_LIST()
168     }
169 };
170 
171 static void goldfish_pic_instance_init(Object *obj)
172 {
173     SysBusDevice *dev = SYS_BUS_DEVICE(obj);
174     GoldfishPICState *s = GOLDFISH_PIC(obj);
175 
176     trace_goldfish_pic_instance_init(s);
177 
178     sysbus_init_mmio(dev, &s->iomem);
179     sysbus_init_irq(dev, &s->irq);
180 
181     qdev_init_gpio_in(DEVICE(obj), goldfish_irq_request, GOLDFISH_PIC_IRQ_NB);
182 }
183 
184 static Property goldfish_pic_properties[] = {
185     DEFINE_PROP_UINT8("index", GoldfishPICState, idx, 0),
186     DEFINE_PROP_END_OF_LIST(),
187 };
188 
189 static void goldfish_pic_class_init(ObjectClass *oc, void *data)
190 {
191     DeviceClass *dc = DEVICE_CLASS(oc);
192     InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(oc);
193 
194     device_class_set_legacy_reset(dc, goldfish_pic_reset);
195     dc->realize = goldfish_pic_realize;
196     dc->vmsd = &vmstate_goldfish_pic;
197     ic->get_statistics = goldfish_pic_get_statistics;
198     ic->print_info = goldfish_pic_print_info;
199     device_class_set_props(dc, goldfish_pic_properties);
200 }
201 
202 static const TypeInfo goldfish_pic_info = {
203     .name = TYPE_GOLDFISH_PIC,
204     .parent = TYPE_SYS_BUS_DEVICE,
205     .class_init = goldfish_pic_class_init,
206     .instance_init = goldfish_pic_instance_init,
207     .instance_size = sizeof(GoldfishPICState),
208     .interfaces = (InterfaceInfo[]) {
209          { TYPE_INTERRUPT_STATS_PROVIDER },
210          { }
211     },
212 };
213 
214 static void goldfish_pic_register_types(void)
215 {
216     type_register_static(&goldfish_pic_info);
217 }
218 
219 type_init(goldfish_pic_register_types)
220