127407470SHelge Deller /* 227407470SHelge Deller * HP Diva GSP controller 327407470SHelge Deller * 427407470SHelge Deller * The Diva PCI boards are Remote Management cards for PA-RISC machines. 527407470SHelge Deller * They come with built-in 16550A multi UARTs for serial consoles 627407470SHelge Deller * and a mailbox-like memory area for hardware auto-reboot functionality. 727407470SHelge Deller * GSP stands for "Guardian Service Processor". Later products were marketed 827407470SHelge Deller * "Management Processor" (MP). 927407470SHelge Deller * 1027407470SHelge Deller * Diva cards are multifunctional cards. The first part, the aux port, 1127407470SHelge Deller * is on physical machines not useable but we still try to mimic it here. 1227407470SHelge Deller * 1327407470SHelge Deller * SPDX-License-Identifier: GPL-2.0-or-later 1427407470SHelge Deller * 1527407470SHelge Deller * Copyright (c) 2025 Helge Deller <deller@gmx.de> 1627407470SHelge Deller */ 1727407470SHelge Deller 1827407470SHelge Deller #include "qemu/osdep.h" 1927407470SHelge Deller #include "qemu/units.h" 2027407470SHelge Deller #include "hw/char/serial.h" 2127407470SHelge Deller #include "hw/irq.h" 2227407470SHelge Deller #include "hw/pci/pci_device.h" 2327407470SHelge Deller #include "hw/qdev-properties.h" 2427407470SHelge Deller #include "hw/qdev-properties-system.h" 2527407470SHelge Deller #include "migration/vmstate.h" 2627407470SHelge Deller 2727407470SHelge Deller #define PCI_DEVICE_ID_HP_DIVA 0x1048 2827407470SHelge Deller /* various DIVA GSP cards: */ 2927407470SHelge Deller #define PCI_DEVICE_ID_HP_DIVA_TOSCA1 0x1049 3027407470SHelge Deller #define PCI_DEVICE_ID_HP_DIVA_TOSCA2 0x104A 3127407470SHelge Deller #define PCI_DEVICE_ID_HP_DIVA_MAESTRO 0x104B 3227407470SHelge Deller #define PCI_DEVICE_ID_HP_REO_IOC 0x10f1 3327407470SHelge Deller #define PCI_DEVICE_ID_HP_DIVA_HALFDOME 0x1223 3427407470SHelge Deller #define PCI_DEVICE_ID_HP_DIVA_KEYSTONE 0x1226 3527407470SHelge Deller #define PCI_DEVICE_ID_HP_DIVA_POWERBAR 0x1227 3627407470SHelge Deller #define PCI_DEVICE_ID_HP_DIVA_EVEREST 0x1282 3727407470SHelge Deller #define PCI_DEVICE_ID_HP_DIVA_AUX 0x1290 3827407470SHelge Deller #define PCI_DEVICE_ID_HP_DIVA_RMP3 0x1301 3927407470SHelge Deller #define PCI_DEVICE_ID_HP_DIVA_HURRICANE 0x132a 4027407470SHelge Deller 4127407470SHelge Deller 4227407470SHelge Deller #define PCI_SERIAL_MAX_PORTS 4 4327407470SHelge Deller 4427407470SHelge Deller typedef struct PCIDivaSerialState { 4527407470SHelge Deller PCIDevice dev; 4627407470SHelge Deller MemoryRegion membar; /* for serial ports */ 4727407470SHelge Deller MemoryRegion mailboxbar; /* for hardware mailbox */ 4827407470SHelge Deller uint32_t subvendor; 4927407470SHelge Deller uint32_t ports; 5027407470SHelge Deller char *name[PCI_SERIAL_MAX_PORTS]; 5127407470SHelge Deller SerialState state[PCI_SERIAL_MAX_PORTS]; 5227407470SHelge Deller uint32_t level[PCI_SERIAL_MAX_PORTS]; 5327407470SHelge Deller qemu_irq *irqs; 5427407470SHelge Deller uint8_t prog_if; 5527407470SHelge Deller bool disable; 5627407470SHelge Deller } PCIDivaSerialState; 5727407470SHelge Deller 5827407470SHelge Deller static void diva_pci_exit(PCIDevice *dev) 5927407470SHelge Deller { 6027407470SHelge Deller PCIDivaSerialState *pci = DO_UPCAST(PCIDivaSerialState, dev, dev); 6127407470SHelge Deller SerialState *s; 6227407470SHelge Deller int i; 6327407470SHelge Deller 6427407470SHelge Deller for (i = 0; i < pci->ports; i++) { 6527407470SHelge Deller s = pci->state + i; 6627407470SHelge Deller qdev_unrealize(DEVICE(s)); 6727407470SHelge Deller memory_region_del_subregion(&pci->membar, &s->io); 6827407470SHelge Deller g_free(pci->name[i]); 6927407470SHelge Deller } 7027407470SHelge Deller qemu_free_irqs(pci->irqs, pci->ports); 7127407470SHelge Deller } 7227407470SHelge Deller 7327407470SHelge Deller static void multi_serial_irq_mux(void *opaque, int n, int level) 7427407470SHelge Deller { 7527407470SHelge Deller PCIDivaSerialState *pci = opaque; 7627407470SHelge Deller int i, pending = 0; 7727407470SHelge Deller 7827407470SHelge Deller pci->level[n] = level; 7927407470SHelge Deller for (i = 0; i < pci->ports; i++) { 8027407470SHelge Deller if (pci->level[i]) { 8127407470SHelge Deller pending = 1; 8227407470SHelge Deller } 8327407470SHelge Deller } 8427407470SHelge Deller pci_set_irq(&pci->dev, pending); 8527407470SHelge Deller } 8627407470SHelge Deller 8727407470SHelge Deller struct diva_info { 8827407470SHelge Deller unsigned int nports:4; /* number of serial ports */ 8927407470SHelge Deller unsigned int omask:12; /* offset mask: BIT(1) -> offset 8 */ 9027407470SHelge Deller }; 9127407470SHelge Deller 9227407470SHelge Deller static struct diva_info diva_get_diva_info(PCIDeviceClass *pc) 9327407470SHelge Deller { 9427407470SHelge Deller switch (pc->subsystem_id) { 9527407470SHelge Deller case PCI_DEVICE_ID_HP_DIVA_POWERBAR: 9627407470SHelge Deller case PCI_DEVICE_ID_HP_DIVA_HURRICANE: 9727407470SHelge Deller return (struct diva_info) { .nports = 1, 9827407470SHelge Deller .omask = BIT(0) }; 9927407470SHelge Deller case PCI_DEVICE_ID_HP_DIVA_TOSCA2: 10027407470SHelge Deller return (struct diva_info) { .nports = 2, 10127407470SHelge Deller .omask = BIT(0) | BIT(1) }; 10227407470SHelge Deller case PCI_DEVICE_ID_HP_DIVA_TOSCA1: 10327407470SHelge Deller case PCI_DEVICE_ID_HP_DIVA_HALFDOME: 10427407470SHelge Deller case PCI_DEVICE_ID_HP_DIVA_KEYSTONE: 10527407470SHelge Deller return (struct diva_info) { .nports = 3, 10627407470SHelge Deller .omask = BIT(0) | BIT(1) | BIT(2) }; 10727407470SHelge Deller case PCI_DEVICE_ID_HP_DIVA_EVEREST: /* e.g. in rp3410 */ 10827407470SHelge Deller return (struct diva_info) { .nports = 3, 10927407470SHelge Deller .omask = BIT(0) | BIT(2) | BIT(7) }; 11027407470SHelge Deller case PCI_DEVICE_ID_HP_DIVA_MAESTRO: 11127407470SHelge Deller return (struct diva_info) { .nports = 4, 11227407470SHelge Deller .omask = BIT(0) | BIT(1) | BIT(2) | BIT(7) }; 11327407470SHelge Deller } 11427407470SHelge Deller g_assert_not_reached(); 11527407470SHelge Deller } 11627407470SHelge Deller 11727407470SHelge Deller 11827407470SHelge Deller static void diva_pci_realize(PCIDevice *dev, Error **errp) 11927407470SHelge Deller { 12027407470SHelge Deller PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev); 12127407470SHelge Deller PCIDivaSerialState *pci = DO_UPCAST(PCIDivaSerialState, dev, dev); 12227407470SHelge Deller SerialState *s; 12327407470SHelge Deller struct diva_info di = diva_get_diva_info(pc); 12427407470SHelge Deller size_t i, offset = 0; 12527407470SHelge Deller size_t portmask = di.omask; 12627407470SHelge Deller 12727407470SHelge Deller pci->dev.config[PCI_CLASS_PROG] = pci->prog_if; 12827407470SHelge Deller pci->dev.config[PCI_INTERRUPT_PIN] = 0x01; 12927407470SHelge Deller memory_region_init(&pci->membar, OBJECT(pci), "serial_ports", 4096); 13027407470SHelge Deller pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &pci->membar); 13127407470SHelge Deller pci->irqs = qemu_allocate_irqs(multi_serial_irq_mux, pci, di.nports); 13227407470SHelge Deller 13327407470SHelge Deller for (i = 0; i < di.nports; i++) { 13427407470SHelge Deller s = pci->state + i; 13527407470SHelge Deller if (!qdev_realize(DEVICE(s), NULL, errp)) { 13627407470SHelge Deller diva_pci_exit(dev); 13727407470SHelge Deller return; 13827407470SHelge Deller } 13927407470SHelge Deller s->irq = pci->irqs[i]; 14027407470SHelge Deller pci->name[i] = g_strdup_printf("uart #%zu", i + 1); 14127407470SHelge Deller memory_region_init_io(&s->io, OBJECT(pci), &serial_io_ops, s, 14227407470SHelge Deller pci->name[i], 8); 14327407470SHelge Deller 14427407470SHelge Deller /* calculate offset of given port based on bitmask */ 14527407470SHelge Deller while ((portmask & BIT(0)) == 0) { 14627407470SHelge Deller offset += 8; 14727407470SHelge Deller portmask >>= 1; 14827407470SHelge Deller } 14927407470SHelge Deller memory_region_add_subregion(&pci->membar, offset, &s->io); 15027407470SHelge Deller offset += 8; 15127407470SHelge Deller portmask >>= 1; 15227407470SHelge Deller pci->ports++; 15327407470SHelge Deller } 15427407470SHelge Deller 15527407470SHelge Deller /* mailbox bar */ 15627407470SHelge Deller memory_region_init(&pci->mailboxbar, OBJECT(pci), "mailbox", 128 * KiB); 15727407470SHelge Deller pci_register_bar(&pci->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY | 15827407470SHelge Deller PCI_BASE_ADDRESS_MEM_PREFETCH, &pci->mailboxbar); 15927407470SHelge Deller } 16027407470SHelge Deller 16127407470SHelge Deller static const VMStateDescription vmstate_pci_diva = { 16227407470SHelge Deller .name = "pci-diva-serial", 16327407470SHelge Deller .version_id = 1, 16427407470SHelge Deller .minimum_version_id = 1, 16527407470SHelge Deller .fields = (const VMStateField[]) { 16627407470SHelge Deller VMSTATE_PCI_DEVICE(dev, PCIDivaSerialState), 16727407470SHelge Deller VMSTATE_STRUCT_ARRAY(state, PCIDivaSerialState, PCI_SERIAL_MAX_PORTS, 16827407470SHelge Deller 0, vmstate_serial, SerialState), 16927407470SHelge Deller VMSTATE_UINT32_ARRAY(level, PCIDivaSerialState, PCI_SERIAL_MAX_PORTS), 17027407470SHelge Deller VMSTATE_BOOL(disable, PCIDivaSerialState), 17127407470SHelge Deller VMSTATE_END_OF_LIST() 17227407470SHelge Deller } 17327407470SHelge Deller }; 17427407470SHelge Deller 17527407470SHelge Deller static const Property diva_serial_properties[] = { 17627407470SHelge Deller DEFINE_PROP_BOOL("disable", PCIDivaSerialState, disable, false), 17727407470SHelge Deller DEFINE_PROP_CHR("chardev1", PCIDivaSerialState, state[0].chr), 17827407470SHelge Deller DEFINE_PROP_CHR("chardev2", PCIDivaSerialState, state[1].chr), 17927407470SHelge Deller DEFINE_PROP_CHR("chardev3", PCIDivaSerialState, state[2].chr), 18027407470SHelge Deller DEFINE_PROP_CHR("chardev4", PCIDivaSerialState, state[3].chr), 18127407470SHelge Deller DEFINE_PROP_UINT8("prog_if", PCIDivaSerialState, prog_if, 0x02), 18227407470SHelge Deller DEFINE_PROP_UINT32("subvendor", PCIDivaSerialState, subvendor, 18327407470SHelge Deller PCI_DEVICE_ID_HP_DIVA_TOSCA1), 18427407470SHelge Deller }; 18527407470SHelge Deller 186*12d1a768SPhilippe Mathieu-Daudé static void diva_serial_class_initfn(ObjectClass *klass, const void *data) 18727407470SHelge Deller { 18827407470SHelge Deller DeviceClass *dc = DEVICE_CLASS(klass); 18927407470SHelge Deller PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass); 19027407470SHelge Deller pc->realize = diva_pci_realize; 19127407470SHelge Deller pc->exit = diva_pci_exit; 19227407470SHelge Deller pc->vendor_id = PCI_VENDOR_ID_HP; 19327407470SHelge Deller pc->device_id = PCI_DEVICE_ID_HP_DIVA; 19427407470SHelge Deller pc->subsystem_vendor_id = PCI_VENDOR_ID_HP; 19527407470SHelge Deller pc->subsystem_id = PCI_DEVICE_ID_HP_DIVA_TOSCA1; 19627407470SHelge Deller pc->revision = 3; 19727407470SHelge Deller pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL; 19827407470SHelge Deller dc->vmsd = &vmstate_pci_diva; 19927407470SHelge Deller device_class_set_props(dc, diva_serial_properties); 20027407470SHelge Deller set_bit(DEVICE_CATEGORY_INPUT, dc->categories); 20127407470SHelge Deller } 20227407470SHelge Deller 20327407470SHelge Deller static void diva_serial_init(Object *o) 20427407470SHelge Deller { 20527407470SHelge Deller PCIDevice *dev = PCI_DEVICE(o); 20627407470SHelge Deller PCIDivaSerialState *pms = DO_UPCAST(PCIDivaSerialState, dev, dev); 20727407470SHelge Deller struct diva_info di = diva_get_diva_info(PCI_DEVICE_GET_CLASS(dev)); 20827407470SHelge Deller size_t i; 20927407470SHelge Deller 21027407470SHelge Deller for (i = 0; i < di.nports; i++) { 21127407470SHelge Deller object_initialize_child(o, "serial[*]", &pms->state[i], TYPE_SERIAL); 21227407470SHelge Deller } 21327407470SHelge Deller } 21427407470SHelge Deller 21527407470SHelge Deller 21627407470SHelge Deller /* Diva-aux is the driver for portion 0 of the multifunction PCI device */ 21727407470SHelge Deller 21827407470SHelge Deller struct DivaAuxState { 21927407470SHelge Deller PCIDevice dev; 22027407470SHelge Deller MemoryRegion mem; 22127407470SHelge Deller qemu_irq irq; 22227407470SHelge Deller }; 22327407470SHelge Deller 22427407470SHelge Deller #define TYPE_DIVA_AUX "diva-aux" 22527407470SHelge Deller OBJECT_DECLARE_SIMPLE_TYPE(DivaAuxState, DIVA_AUX) 22627407470SHelge Deller 22727407470SHelge Deller static void diva_aux_realize(PCIDevice *dev, Error **errp) 22827407470SHelge Deller { 22927407470SHelge Deller DivaAuxState *pci = DO_UPCAST(DivaAuxState, dev, dev); 23027407470SHelge Deller 23127407470SHelge Deller pci->dev.config[PCI_CLASS_PROG] = 0x02; 23227407470SHelge Deller pci->dev.config[PCI_INTERRUPT_PIN] = 0x01; 23327407470SHelge Deller pci->irq = pci_allocate_irq(&pci->dev); 23427407470SHelge Deller 23527407470SHelge Deller memory_region_init(&pci->mem, OBJECT(pci), "mem", 16); 23627407470SHelge Deller pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &pci->mem); 23727407470SHelge Deller } 23827407470SHelge Deller 23927407470SHelge Deller static void diva_aux_exit(PCIDevice *dev) 24027407470SHelge Deller { 24127407470SHelge Deller DivaAuxState *pci = DO_UPCAST(DivaAuxState, dev, dev); 24227407470SHelge Deller qemu_free_irq(pci->irq); 24327407470SHelge Deller } 24427407470SHelge Deller 245*12d1a768SPhilippe Mathieu-Daudé static void diva_aux_class_initfn(ObjectClass *klass, const void *data) 24627407470SHelge Deller { 24727407470SHelge Deller DeviceClass *dc = DEVICE_CLASS(klass); 24827407470SHelge Deller PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass); 24927407470SHelge Deller pc->realize = diva_aux_realize; 25027407470SHelge Deller pc->exit = diva_aux_exit; 25127407470SHelge Deller pc->vendor_id = PCI_VENDOR_ID_HP; 25227407470SHelge Deller pc->device_id = PCI_DEVICE_ID_HP_DIVA_AUX; 25327407470SHelge Deller pc->subsystem_vendor_id = PCI_VENDOR_ID_HP; 25427407470SHelge Deller pc->subsystem_id = 0x1291; 25527407470SHelge Deller pc->revision = 1; 25627407470SHelge Deller pc->class_id = PCI_CLASS_COMMUNICATION_MULTISERIAL; 25727407470SHelge Deller set_bit(DEVICE_CATEGORY_MISC, dc->categories); 25827407470SHelge Deller dc->user_creatable = false; 25927407470SHelge Deller } 26027407470SHelge Deller 26127407470SHelge Deller static void diva_aux_init(Object *o) 26227407470SHelge Deller { 26327407470SHelge Deller } 26427407470SHelge Deller 26527407470SHelge Deller static const TypeInfo diva_aux_info = { 26627407470SHelge Deller .name = TYPE_DIVA_AUX, 26727407470SHelge Deller .parent = TYPE_PCI_DEVICE, 26827407470SHelge Deller .instance_size = sizeof(DivaAuxState), 26927407470SHelge Deller .instance_init = diva_aux_init, 27027407470SHelge Deller .class_init = diva_aux_class_initfn, 27127407470SHelge Deller .interfaces = (InterfaceInfo[]) { 27227407470SHelge Deller { INTERFACE_CONVENTIONAL_PCI_DEVICE }, 27327407470SHelge Deller { }, 27427407470SHelge Deller }, 27527407470SHelge Deller }; 27627407470SHelge Deller 27727407470SHelge Deller 27827407470SHelge Deller 27927407470SHelge Deller static const TypeInfo diva_serial_pci_info = { 28027407470SHelge Deller .name = "diva-gsp", 28127407470SHelge Deller .parent = TYPE_PCI_DEVICE, 28227407470SHelge Deller .instance_size = sizeof(PCIDivaSerialState), 28327407470SHelge Deller .instance_init = diva_serial_init, 28427407470SHelge Deller .class_init = diva_serial_class_initfn, 28527407470SHelge Deller .interfaces = (InterfaceInfo[]) { 28627407470SHelge Deller { INTERFACE_CONVENTIONAL_PCI_DEVICE }, 28727407470SHelge Deller { }, 28827407470SHelge Deller }, 28927407470SHelge Deller }; 29027407470SHelge Deller 29127407470SHelge Deller static void diva_pci_register_type(void) 29227407470SHelge Deller { 29327407470SHelge Deller type_register_static(&diva_serial_pci_info); 29427407470SHelge Deller type_register_static(&diva_aux_info); 29527407470SHelge Deller } 29627407470SHelge Deller 29727407470SHelge Deller type_init(diva_pci_register_type) 298