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 "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 23 enum { 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 31 static 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 42 static 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 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 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 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