goldfish_pic.c (5648B)
1/* 2 * SPDX-License-Identifer: 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 "monitor/monitor.h" 16#include "qemu/log.h" 17#include "trace.h" 18#include "hw/intc/intc.h" 19#include "hw/intc/goldfish_pic.h" 20 21/* registers */ 22 23enum { 24 REG_STATUS = 0x00, 25 REG_IRQ_PENDING = 0x04, 26 REG_IRQ_DISABLE_ALL = 0x08, 27 REG_DISABLE = 0x0c, 28 REG_ENABLE = 0x10, 29}; 30 31static bool goldfish_pic_get_statistics(InterruptStatsProvider *obj, 32 uint64_t **irq_counts, 33 unsigned int *nb_irqs) 34{ 35 GoldfishPICState *s = GOLDFISH_PIC(obj); 36 37 *irq_counts = s->stats_irq_count; 38 *nb_irqs = ARRAY_SIZE(s->stats_irq_count); 39 return true; 40} 41 42static void goldfish_pic_print_info(InterruptStatsProvider *obj, Monitor *mon) 43{ 44 GoldfishPICState *s = GOLDFISH_PIC(obj); 45 monitor_printf(mon, "goldfish-pic.%d: pending=0x%08x enabled=0x%08x\n", 46 s->idx, s->pending, s->enabled); 47} 48 49static 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 58static 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 73static 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 100static 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 127static 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 136static 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 150static 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 160static const VMStateDescription vmstate_goldfish_pic = { 161 .name = "goldfish_pic", 162 .version_id = 1, 163 .minimum_version_id = 1, 164 .fields = (VMStateField[]) { 165 VMSTATE_UINT32(pending, GoldfishPICState), 166 VMSTATE_UINT32(enabled, GoldfishPICState), 167 VMSTATE_END_OF_LIST() 168 } 169}; 170 171static 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 184static Property goldfish_pic_properties[] = { 185 DEFINE_PROP_UINT8("index", GoldfishPICState, idx, 0), 186 DEFINE_PROP_END_OF_LIST(), 187}; 188 189static 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 dc->reset = 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 202static 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 214static void goldfish_pic_register_types(void) 215{ 216 type_register_static(&goldfish_pic_info); 217} 218 219type_init(goldfish_pic_register_types)