187855593SLaurent Vivier /* 265b4c8c7SPhilippe Mathieu-Daudé * SPDX-License-Identifier: GPL-2.0-or-later 387855593SLaurent Vivier * 487855593SLaurent Vivier * Goldfish PIC 587855593SLaurent Vivier * 687855593SLaurent Vivier * (c) 2020 Laurent Vivier <laurent@vivier.eu> 787855593SLaurent Vivier * 887855593SLaurent Vivier */ 987855593SLaurent Vivier 1087855593SLaurent Vivier #include "qemu/osdep.h" 1187855593SLaurent Vivier #include "hw/irq.h" 1287855593SLaurent Vivier #include "hw/qdev-properties.h" 1387855593SLaurent Vivier #include "hw/sysbus.h" 1487855593SLaurent Vivier #include "migration/vmstate.h" 1587855593SLaurent Vivier #include "qemu/log.h" 1687855593SLaurent Vivier #include "trace.h" 1787855593SLaurent Vivier #include "hw/intc/intc.h" 1887855593SLaurent Vivier #include "hw/intc/goldfish_pic.h" 1987855593SLaurent Vivier 2087855593SLaurent Vivier /* registers */ 2187855593SLaurent Vivier 2287855593SLaurent Vivier enum { 2387855593SLaurent Vivier REG_STATUS = 0x00, 2487855593SLaurent Vivier REG_IRQ_PENDING = 0x04, 2587855593SLaurent Vivier REG_IRQ_DISABLE_ALL = 0x08, 2687855593SLaurent Vivier REG_DISABLE = 0x0c, 2787855593SLaurent Vivier REG_ENABLE = 0x10, 2887855593SLaurent Vivier }; 2987855593SLaurent Vivier 3087855593SLaurent Vivier static bool goldfish_pic_get_statistics(InterruptStatsProvider *obj, 3187855593SLaurent Vivier uint64_t **irq_counts, 3287855593SLaurent Vivier unsigned int *nb_irqs) 3387855593SLaurent Vivier { 3487855593SLaurent Vivier GoldfishPICState *s = GOLDFISH_PIC(obj); 3587855593SLaurent Vivier 3687855593SLaurent Vivier *irq_counts = s->stats_irq_count; 3787855593SLaurent Vivier *nb_irqs = ARRAY_SIZE(s->stats_irq_count); 3887855593SLaurent Vivier return true; 3987855593SLaurent Vivier } 4087855593SLaurent Vivier 41b2580720SPhilippe Mathieu-Daudé static void goldfish_pic_print_info(InterruptStatsProvider *obj, GString *buf) 4287855593SLaurent Vivier { 4387855593SLaurent Vivier GoldfishPICState *s = GOLDFISH_PIC(obj); 44b2580720SPhilippe Mathieu-Daudé g_string_append_printf(buf, 45b2580720SPhilippe Mathieu-Daudé "goldfish-pic.%d: pending=0x%08x enabled=0x%08x\n", 4687855593SLaurent Vivier s->idx, s->pending, s->enabled); 4787855593SLaurent Vivier } 4887855593SLaurent Vivier 4987855593SLaurent Vivier static void goldfish_pic_update(GoldfishPICState *s) 5087855593SLaurent Vivier { 5187855593SLaurent Vivier if (s->pending & s->enabled) { 5287855593SLaurent Vivier qemu_irq_raise(s->irq); 5387855593SLaurent Vivier } else { 5487855593SLaurent Vivier qemu_irq_lower(s->irq); 5587855593SLaurent Vivier } 5687855593SLaurent Vivier } 5787855593SLaurent Vivier 5887855593SLaurent Vivier static void goldfish_irq_request(void *opaque, int irq, int level) 5987855593SLaurent Vivier { 6087855593SLaurent Vivier GoldfishPICState *s = opaque; 6187855593SLaurent Vivier 6287855593SLaurent Vivier trace_goldfish_irq_request(s, s->idx, irq, level); 6387855593SLaurent Vivier 6487855593SLaurent Vivier if (level) { 6587855593SLaurent Vivier s->pending |= 1 << irq; 6687855593SLaurent Vivier s->stats_irq_count[irq]++; 6787855593SLaurent Vivier } else { 6887855593SLaurent Vivier s->pending &= ~(1 << irq); 6987855593SLaurent Vivier } 7087855593SLaurent Vivier goldfish_pic_update(s); 7187855593SLaurent Vivier } 7287855593SLaurent Vivier 7387855593SLaurent Vivier static uint64_t goldfish_pic_read(void *opaque, hwaddr addr, 7487855593SLaurent Vivier unsigned size) 7587855593SLaurent Vivier { 7687855593SLaurent Vivier GoldfishPICState *s = opaque; 7787855593SLaurent Vivier uint64_t value = 0; 7887855593SLaurent Vivier 7987855593SLaurent Vivier switch (addr) { 8087855593SLaurent Vivier case REG_STATUS: 8187855593SLaurent Vivier /* The number of pending interrupts (0 to 32) */ 8287855593SLaurent Vivier value = ctpop32(s->pending & s->enabled); 8387855593SLaurent Vivier break; 8487855593SLaurent Vivier case REG_IRQ_PENDING: 8587855593SLaurent Vivier /* The pending interrupt mask */ 8687855593SLaurent Vivier value = s->pending & s->enabled; 8787855593SLaurent Vivier break; 8887855593SLaurent Vivier default: 8987855593SLaurent Vivier qemu_log_mask(LOG_UNIMP, 9087855593SLaurent Vivier "%s: unimplemented register read 0x%02"HWADDR_PRIx"\n", 9187855593SLaurent Vivier __func__, addr); 9287855593SLaurent Vivier break; 9387855593SLaurent Vivier } 9487855593SLaurent Vivier 9587855593SLaurent Vivier trace_goldfish_pic_read(s, s->idx, addr, size, value); 9687855593SLaurent Vivier 9787855593SLaurent Vivier return value; 9887855593SLaurent Vivier } 9987855593SLaurent Vivier 10087855593SLaurent Vivier static void goldfish_pic_write(void *opaque, hwaddr addr, 10187855593SLaurent Vivier uint64_t value, unsigned size) 10287855593SLaurent Vivier { 10387855593SLaurent Vivier GoldfishPICState *s = opaque; 10487855593SLaurent Vivier 10587855593SLaurent Vivier trace_goldfish_pic_write(s, s->idx, addr, size, value); 10687855593SLaurent Vivier 10787855593SLaurent Vivier switch (addr) { 10887855593SLaurent Vivier case REG_IRQ_DISABLE_ALL: 10987855593SLaurent Vivier s->enabled = 0; 11087855593SLaurent Vivier s->pending = 0; 11187855593SLaurent Vivier break; 11287855593SLaurent Vivier case REG_DISABLE: 11387855593SLaurent Vivier s->enabled &= ~value; 11487855593SLaurent Vivier break; 11587855593SLaurent Vivier case REG_ENABLE: 11687855593SLaurent Vivier s->enabled |= value; 11787855593SLaurent Vivier break; 11887855593SLaurent Vivier default: 11987855593SLaurent Vivier qemu_log_mask(LOG_UNIMP, 12087855593SLaurent Vivier "%s: unimplemented register write 0x%02"HWADDR_PRIx"\n", 12187855593SLaurent Vivier __func__, addr); 12287855593SLaurent Vivier break; 12387855593SLaurent Vivier } 12487855593SLaurent Vivier goldfish_pic_update(s); 12587855593SLaurent Vivier } 12687855593SLaurent Vivier 12787855593SLaurent Vivier static const MemoryRegionOps goldfish_pic_ops = { 12887855593SLaurent Vivier .read = goldfish_pic_read, 12987855593SLaurent Vivier .write = goldfish_pic_write, 13087855593SLaurent Vivier .endianness = DEVICE_NATIVE_ENDIAN, 13187855593SLaurent Vivier .valid.max_access_size = 4, 13287855593SLaurent Vivier .impl.min_access_size = 4, 13387855593SLaurent Vivier .impl.max_access_size = 4, 13487855593SLaurent Vivier }; 13587855593SLaurent Vivier 13687855593SLaurent Vivier static void goldfish_pic_reset(DeviceState *dev) 13787855593SLaurent Vivier { 13887855593SLaurent Vivier GoldfishPICState *s = GOLDFISH_PIC(dev); 13987855593SLaurent Vivier int i; 14087855593SLaurent Vivier 14187855593SLaurent Vivier trace_goldfish_pic_reset(s, s->idx); 14287855593SLaurent Vivier s->pending = 0; 14387855593SLaurent Vivier s->enabled = 0; 14487855593SLaurent Vivier 14587855593SLaurent Vivier for (i = 0; i < ARRAY_SIZE(s->stats_irq_count); i++) { 14687855593SLaurent Vivier s->stats_irq_count[i] = 0; 14787855593SLaurent Vivier } 14887855593SLaurent Vivier } 14987855593SLaurent Vivier 15087855593SLaurent Vivier static void goldfish_pic_realize(DeviceState *dev, Error **errp) 15187855593SLaurent Vivier { 15287855593SLaurent Vivier GoldfishPICState *s = GOLDFISH_PIC(dev); 15387855593SLaurent Vivier 15487855593SLaurent Vivier trace_goldfish_pic_realize(s, s->idx); 15587855593SLaurent Vivier 15687855593SLaurent Vivier memory_region_init_io(&s->iomem, OBJECT(s), &goldfish_pic_ops, s, 15787855593SLaurent Vivier "goldfish_pic", 0x24); 15887855593SLaurent Vivier } 15987855593SLaurent Vivier 16087855593SLaurent Vivier static const VMStateDescription vmstate_goldfish_pic = { 16187855593SLaurent Vivier .name = "goldfish_pic", 16287855593SLaurent Vivier .version_id = 1, 16387855593SLaurent Vivier .minimum_version_id = 1, 16445b1f81dSRichard Henderson .fields = (const VMStateField[]) { 16587855593SLaurent Vivier VMSTATE_UINT32(pending, GoldfishPICState), 16687855593SLaurent Vivier VMSTATE_UINT32(enabled, GoldfishPICState), 16787855593SLaurent Vivier VMSTATE_END_OF_LIST() 16887855593SLaurent Vivier } 16987855593SLaurent Vivier }; 17087855593SLaurent Vivier 17187855593SLaurent Vivier static void goldfish_pic_instance_init(Object *obj) 17287855593SLaurent Vivier { 17387855593SLaurent Vivier SysBusDevice *dev = SYS_BUS_DEVICE(obj); 17487855593SLaurent Vivier GoldfishPICState *s = GOLDFISH_PIC(obj); 17587855593SLaurent Vivier 17687855593SLaurent Vivier trace_goldfish_pic_instance_init(s); 17787855593SLaurent Vivier 17887855593SLaurent Vivier sysbus_init_mmio(dev, &s->iomem); 17987855593SLaurent Vivier sysbus_init_irq(dev, &s->irq); 18087855593SLaurent Vivier 18187855593SLaurent Vivier qdev_init_gpio_in(DEVICE(obj), goldfish_irq_request, GOLDFISH_PIC_IRQ_NB); 18287855593SLaurent Vivier } 18387855593SLaurent Vivier 184783e3b21SRichard Henderson static const Property goldfish_pic_properties[] = { 18587855593SLaurent Vivier DEFINE_PROP_UINT8("index", GoldfishPICState, idx, 0), 18687855593SLaurent Vivier }; 18787855593SLaurent Vivier 18812d1a768SPhilippe Mathieu-Daudé static void goldfish_pic_class_init(ObjectClass *oc, const void *data) 18987855593SLaurent Vivier { 19087855593SLaurent Vivier DeviceClass *dc = DEVICE_CLASS(oc); 19187855593SLaurent Vivier InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(oc); 19287855593SLaurent Vivier 193e3d08143SPeter Maydell device_class_set_legacy_reset(dc, goldfish_pic_reset); 19487855593SLaurent Vivier dc->realize = goldfish_pic_realize; 19587855593SLaurent Vivier dc->vmsd = &vmstate_goldfish_pic; 19687855593SLaurent Vivier ic->get_statistics = goldfish_pic_get_statistics; 19787855593SLaurent Vivier ic->print_info = goldfish_pic_print_info; 19887855593SLaurent Vivier device_class_set_props(dc, goldfish_pic_properties); 19987855593SLaurent Vivier } 20087855593SLaurent Vivier 20187855593SLaurent Vivier static const TypeInfo goldfish_pic_info = { 20287855593SLaurent Vivier .name = TYPE_GOLDFISH_PIC, 20387855593SLaurent Vivier .parent = TYPE_SYS_BUS_DEVICE, 20487855593SLaurent Vivier .class_init = goldfish_pic_class_init, 20587855593SLaurent Vivier .instance_init = goldfish_pic_instance_init, 20687855593SLaurent Vivier .instance_size = sizeof(GoldfishPICState), 207*2cd09e47SPhilippe Mathieu-Daudé .interfaces = (const InterfaceInfo[]) { 20887855593SLaurent Vivier { TYPE_INTERRUPT_STATS_PROVIDER }, 20987855593SLaurent Vivier { } 21087855593SLaurent Vivier }, 21187855593SLaurent Vivier }; 21287855593SLaurent Vivier 21387855593SLaurent Vivier static void goldfish_pic_register_types(void) 21487855593SLaurent Vivier { 21587855593SLaurent Vivier type_register_static(&goldfish_pic_info); 21687855593SLaurent Vivier } 21787855593SLaurent Vivier 21887855593SLaurent Vivier type_init(goldfish_pic_register_types) 219