aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS1
-rw-r--r--hw/char/Kconfig3
-rw-r--r--hw/char/diva-gsp.c297
-rw-r--r--hw/char/meson.build1
-rw-r--r--hw/display/artist.c9
-rw-r--r--hw/hppa/Kconfig1
-rw-r--r--hw/hppa/machine.c42
-rw-r--r--hw/pci-host/astro.c52
-rw-r--r--include/hw/pci-host/astro.h6
m---------roms/seabios-hppa0
10 files changed, 382 insertions, 30 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index c6859cb..0091bd1 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1193,6 +1193,7 @@ M: Richard Henderson <richard.henderson@linaro.org>
M: Helge Deller <deller@gmx.de>
S: Maintained
F: configs/devices/hppa-softmmu/default.mak
+F: hw/char/diva-gsp.c
F: hw/display/artist.c
F: hw/hppa/
F: hw/input/lasips2.c
diff --git a/hw/char/Kconfig b/hw/char/Kconfig
index 1dc20ee..3f70256 100644
--- a/hw/char/Kconfig
+++ b/hw/char/Kconfig
@@ -66,6 +66,9 @@ config RENESAS_SCI
config AVR_USART
bool
+config DIVA_GSP
+ bool
+
config MCHP_PFSOC_MMUART
bool
select SERIAL
diff --git a/hw/char/diva-gsp.c b/hw/char/diva-gsp.c
new file mode 100644
index 0000000..ecec1f7
--- /dev/null
+++ b/hw/char/diva-gsp.c
@@ -0,0 +1,297 @@
+/*
+ * HP Diva GSP controller
+ *
+ * The Diva PCI boards are Remote Management cards for PA-RISC machines.
+ * They come with built-in 16550A multi UARTs for serial consoles
+ * and a mailbox-like memory area for hardware auto-reboot functionality.
+ * GSP stands for "Guardian Service Processor". Later products were marketed
+ * "Management Processor" (MP).
+ *
+ * Diva cards are multifunctional cards. The first part, the aux port,
+ * is on physical machines not useable but we still try to mimic it here.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Copyright (c) 2025 Helge Deller <deller@gmx.de>
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/units.h"
+#include "hw/char/serial.h"
+#include "hw/irq.h"
+#include "hw/pci/pci_device.h"
+#include "hw/qdev-properties.h"
+#include "hw/qdev-properties-system.h"
+#include "migration/vmstate.h"
+
+#define PCI_DEVICE_ID_HP_DIVA 0x1048
+/* various DIVA GSP cards: */
+#define PCI_DEVICE_ID_HP_DIVA_TOSCA1 0x1049
+#define PCI_DEVICE_ID_HP_DIVA_TOSCA2 0x104A
+#define PCI_DEVICE_ID_HP_DIVA_MAESTRO 0x104B
+#define PCI_DEVICE_ID_HP_REO_IOC 0x10f1
+#define PCI_DEVICE_ID_HP_DIVA_HALFDOME 0x1223
+#define PCI_DEVICE_ID_HP_DIVA_KEYSTONE 0x1226
+#define PCI_DEVICE_ID_HP_DIVA_POWERBAR 0x1227
+#define PCI_DEVICE_ID_HP_DIVA_EVEREST 0x1282
+#define PCI_DEVICE_ID_HP_DIVA_AUX 0x1290
+#define PCI_DEVICE_ID_HP_DIVA_RMP3 0x1301
+#define PCI_DEVICE_ID_HP_DIVA_HURRICANE 0x132a
+
+
+#define PCI_SERIAL_MAX_PORTS 4
+
+typedef struct PCIDivaSerialState {
+ PCIDevice dev;
+ MemoryRegion membar; /* for serial ports */
+ MemoryRegion mailboxbar; /* for hardware mailbox */
+ uint32_t subvendor;
+ uint32_t ports;
+ char *name[PCI_SERIAL_MAX_PORTS];
+ SerialState state[PCI_SERIAL_MAX_PORTS];
+ uint32_t level[PCI_SERIAL_MAX_PORTS];
+ qemu_irq *irqs;
+ uint8_t prog_if;
+ bool disable;
+} PCIDivaSerialState;
+
+static void diva_pci_exit(PCIDevice *dev)
+{
+ PCIDivaSerialState *pci = DO_UPCAST(PCIDivaSerialState, dev, dev);
+ SerialState *s;
+ int i;
+
+ for (i = 0; i < pci->ports; i++) {
+ s = pci->state + i;
+ qdev_unrealize(DEVICE(s));
+ memory_region_del_subregion(&pci->membar, &s->io);
+ g_free(pci->name[i]);
+ }
+ qemu_free_irqs(pci->irqs, pci->ports);
+}
+
+static void multi_serial_irq_mux(void *opaque, int n, int level)
+{
+ PCIDivaSerialState *pci = opaque;
+ int i, pending = 0;
+
+ pci->level[n] = level;
+ for (i = 0; i < pci->ports; i++) {
+ if (pci->level[i]) {
+ pending = 1;
+ }
+ }
+ pci_set_irq(&pci->dev, pending);
+}
+
+struct diva_info {
+ unsigned int nports:4; /* number of serial ports */
+ unsigned int omask:12; /* offset mask: BIT(1) -> offset 8 */
+};
+
+static struct diva_info diva_get_diva_info(PCIDeviceClass *pc)
+{
+ switch (pc->subsystem_id) {
+ case PCI_DEVICE_ID_HP_DIVA_POWERBAR:
+ case PCI_DEVICE_ID_HP_DIVA_HURRICANE:
+ return (struct diva_info) { .nports = 1,
+ .omask = BIT(0) };
+ case PCI_DEVICE_ID_HP_DIVA_TOSCA2:
+ return (struct diva_info) { .nports = 2,
+ .omask = BIT(0) | BIT(1) };
+ case PCI_DEVICE_ID_HP_DIVA_TOSCA1:
+ case PCI_DEVICE_ID_HP_DIVA_HALFDOME:
+ case PCI_DEVICE_ID_HP_DIVA_KEYSTONE:
+ return (struct diva_info) { .nports = 3,
+ .omask = BIT(0) | BIT(1) | BIT(2) };
+ case PCI_DEVICE_ID_HP_DIVA_EVEREST: /* e.g. in rp3410 */
+ return (struct diva_info) { .nports = 3,
+ .omask = BIT(0) | BIT(2) | BIT(7) };
+ case PCI_DEVICE_ID_HP_DIVA_MAESTRO:
+ return (struct diva_info) { .nports = 4,
+ .omask = BIT(0) | BIT(1) | BIT(2) | BIT(7) };
+ }
+ g_assert_not_reached();
+}
+
+
+static void diva_pci_realize(PCIDevice *dev, Error **errp)
+{
+ PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
+ PCIDivaSerialState *pci = DO_UPCAST(PCIDivaSerialState, dev, dev);
+ SerialState *s;
+ struct diva_info di = diva_get_diva_info(pc);
+ size_t i, offset = 0;
+ size_t portmask = di.omask;
+
+ pci->dev.config[PCI_CLASS_PROG] = pci->prog_if;
+ pci->dev.config[PCI_INTERRUPT_PIN] = 0x01;
+ memory_region_init(&pci->membar, OBJECT(pci), "serial_ports", 4096);
+ pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &pci->membar);
+ pci->irqs = qemu_allocate_irqs(multi_serial_irq_mux, pci, di.nports);
+
+ for (i = 0; i < di.nports; i++) {
+ s = pci->state + i;
+ if (!qdev_realize(DEVICE(s), NULL, errp)) {
+ diva_pci_exit(dev);
+ return;
+ }
+ s->irq = pci->irqs[i];
+ pci->name[i] = g_strdup_printf("uart #%zu", i + 1);
+ memory_region_init_io(&s->io, OBJECT(pci), &serial_io_ops, s,
+ pci->name[i], 8);
+
+ /* calculate offset of given port based on bitmask */
+ while ((portmask & BIT(0)) == 0) {
+ offset += 8;
+ portmask >>= 1;
+ }
+ memory_region_add_subregion(&pci->membar, offset, &s->io);
+ offset += 8;
+ portmask >>= 1;
+ pci->ports++;
+ }
+
+ /* mailbox bar */
+ memory_region_init(&pci->mailboxbar, OBJECT(pci), "mailbox", 128 * KiB);
+ pci_register_bar(&pci->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY |
+ PCI_BASE_ADDRESS_MEM_PREFETCH, &pci->mailboxbar);
+}
+
+static const VMStateDescription vmstate_pci_diva = {
+ .name = "pci-diva-serial",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const VMStateField[]) {
+ VMSTATE_PCI_DEVICE(dev, PCIDivaSerialState),
+ VMSTATE_STRUCT_ARRAY(state, PCIDivaSerialState, PCI_SERIAL_MAX_PORTS,
+ 0, vmstate_serial, SerialState),
+ VMSTATE_UINT32_ARRAY(level, PCIDivaSerialState, PCI_SERIAL_MAX_PORTS),
+ VMSTATE_BOOL(disable, PCIDivaSerialState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const Property diva_serial_properties[] = {
+ DEFINE_PROP_BOOL("disable", PCIDivaSerialState, disable, false),
+ DEFINE_PROP_CHR("chardev1", PCIDivaSerialState, state[0].chr),
+ DEFINE_PROP_CHR("chardev2", PCIDivaSerialState, state[1].chr),
+ DEFINE_PROP_CHR("chardev3", PCIDivaSerialState, state[2].chr),
+ DEFINE_PROP_CHR("chardev4", PCIDivaSerialState, state[3].chr),
+ DEFINE_PROP_UINT8("prog_if", PCIDivaSerialState, prog_if, 0x02),
+ DEFINE_PROP_UINT32("subvendor", PCIDivaSerialState, subvendor,
+ PCI_DEVICE_ID_HP_DIVA_TOSCA1),
+};
+
+static void diva_serial_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass);
+ pc->realize = diva_pci_realize;
+ pc->exit = diva_pci_exit;
+ pc->vendor_id = PCI_VENDOR_ID_HP;
+ pc->device_id = PCI_DEVICE_ID_HP_DIVA;
+ pc->subsystem_vendor_id = PCI_VENDOR_ID_HP;
+ pc->subsystem_id = PCI_DEVICE_ID_HP_DIVA_TOSCA1;
+ pc->revision = 3;
+ pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL;
+ dc->vmsd = &vmstate_pci_diva;
+ device_class_set_props(dc, diva_serial_properties);
+ set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
+}
+
+static void diva_serial_init(Object *o)
+{
+ PCIDevice *dev = PCI_DEVICE(o);
+ PCIDivaSerialState *pms = DO_UPCAST(PCIDivaSerialState, dev, dev);
+ struct diva_info di = diva_get_diva_info(PCI_DEVICE_GET_CLASS(dev));
+ size_t i;
+
+ for (i = 0; i < di.nports; i++) {
+ object_initialize_child(o, "serial[*]", &pms->state[i], TYPE_SERIAL);
+ }
+}
+
+
+/* Diva-aux is the driver for portion 0 of the multifunction PCI device */
+
+struct DivaAuxState {
+ PCIDevice dev;
+ MemoryRegion mem;
+ qemu_irq irq;
+};
+
+#define TYPE_DIVA_AUX "diva-aux"
+OBJECT_DECLARE_SIMPLE_TYPE(DivaAuxState, DIVA_AUX)
+
+static void diva_aux_realize(PCIDevice *dev, Error **errp)
+{
+ DivaAuxState *pci = DO_UPCAST(DivaAuxState, dev, dev);
+
+ pci->dev.config[PCI_CLASS_PROG] = 0x02;
+ pci->dev.config[PCI_INTERRUPT_PIN] = 0x01;
+ pci->irq = pci_allocate_irq(&pci->dev);
+
+ memory_region_init(&pci->mem, OBJECT(pci), "mem", 16);
+ pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &pci->mem);
+}
+
+static void diva_aux_exit(PCIDevice *dev)
+{
+ DivaAuxState *pci = DO_UPCAST(DivaAuxState, dev, dev);
+ qemu_free_irq(pci->irq);
+}
+
+static void diva_aux_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass);
+ pc->realize = diva_aux_realize;
+ pc->exit = diva_aux_exit;
+ pc->vendor_id = PCI_VENDOR_ID_HP;
+ pc->device_id = PCI_DEVICE_ID_HP_DIVA_AUX;
+ pc->subsystem_vendor_id = PCI_VENDOR_ID_HP;
+ pc->subsystem_id = 0x1291;
+ pc->revision = 1;
+ pc->class_id = PCI_CLASS_COMMUNICATION_MULTISERIAL;
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+ dc->user_creatable = false;
+}
+
+static void diva_aux_init(Object *o)
+{
+}
+
+static const TypeInfo diva_aux_info = {
+ .name = TYPE_DIVA_AUX,
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(DivaAuxState),
+ .instance_init = diva_aux_init,
+ .class_init = diva_aux_class_initfn,
+ .interfaces = (InterfaceInfo[]) {
+ { INTERFACE_CONVENTIONAL_PCI_DEVICE },
+ { },
+ },
+};
+
+
+
+static const TypeInfo diva_serial_pci_info = {
+ .name = "diva-gsp",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIDivaSerialState),
+ .instance_init = diva_serial_init,
+ .class_init = diva_serial_class_initfn,
+ .interfaces = (InterfaceInfo[]) {
+ { INTERFACE_CONVENTIONAL_PCI_DEVICE },
+ { },
+ },
+};
+
+static void diva_pci_register_type(void)
+{
+ type_register_static(&diva_serial_pci_info);
+ type_register_static(&diva_aux_info);
+}
+
+type_init(diva_pci_register_type)
diff --git a/hw/char/meson.build b/hw/char/meson.build
index ed3529c..86ee808 100644
--- a/hw/char/meson.build
+++ b/hw/char/meson.build
@@ -20,6 +20,7 @@ system_ss.add(when: 'CONFIG_SHAKTI_UART', if_true: files('shakti_uart.c'))
system_ss.add(when: 'CONFIG_VIRTIO_SERIAL', if_true: files('virtio-console.c'))
system_ss.add(when: 'CONFIG_XEN_BUS', if_true: files('xen_console.c'))
system_ss.add(when: 'CONFIG_XILINX', if_true: files('xilinx_uartlite.c'))
+system_ss.add(when: 'CONFIG_DIVA_GSP', if_true: files('diva-gsp.c'))
system_ss.add(when: 'CONFIG_AVR_USART', if_true: files('avr_usart.c'))
system_ss.add(when: 'CONFIG_COLDFIRE', if_true: files('mcf_uart.c'))
diff --git a/hw/display/artist.c b/hw/display/artist.c
index 8b719b1..f24c1d8 100644
--- a/hw/display/artist.c
+++ b/hw/display/artist.c
@@ -48,6 +48,7 @@ struct ARTISTState {
struct vram_buffer vram_buffer[16];
+ bool disable;
uint16_t width;
uint16_t height;
uint16_t depth;
@@ -1211,8 +1212,8 @@ static uint64_t artist_reg_read(void *opaque, hwaddr addr, unsigned size)
break;
case 0x380004:
- /* 0x02000000 Buserror */
- val = 0x6dc20006;
+ /* magic number detected by SeaBIOS-hppa */
+ val = s->disable ? 0 : 0x6dc20006;
break;
default:
@@ -1432,7 +1433,7 @@ static int vmstate_artist_post_load(void *opaque, int version_id)
static const VMStateDescription vmstate_artist = {
.name = "artist",
- .version_id = 2,
+ .version_id = 3,
.minimum_version_id = 2,
.post_load = vmstate_artist_post_load,
.fields = (const VMStateField[]) {
@@ -1470,6 +1471,7 @@ static const VMStateDescription vmstate_artist = {
VMSTATE_UINT32(font_write1, ARTISTState),
VMSTATE_UINT32(font_write2, ARTISTState),
VMSTATE_UINT32(font_write_pos_y, ARTISTState),
+ VMSTATE_BOOL(disable, ARTISTState),
VMSTATE_END_OF_LIST()
}
};
@@ -1478,6 +1480,7 @@ static const Property artist_properties[] = {
DEFINE_PROP_UINT16("width", ARTISTState, width, 1280),
DEFINE_PROP_UINT16("height", ARTISTState, height, 1024),
DEFINE_PROP_UINT16("depth", ARTISTState, depth, 8),
+ DEFINE_PROP_BOOL("disable", ARTISTState, disable, false),
};
static void artist_reset(DeviceState *qdev)
diff --git a/hw/hppa/Kconfig b/hw/hppa/Kconfig
index 9312c42..cab2104 100644
--- a/hw/hppa/Kconfig
+++ b/hw/hppa/Kconfig
@@ -11,6 +11,7 @@ config HPPA_B160L
select LASI
select SERIAL_MM
select SERIAL_PCI
+ select DIVA_GSP
select ISA_BUS
select I8259
select IDE_CMD646
diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c
index b6135d9..c5f2476 100644
--- a/hw/hppa/machine.c
+++ b/hw/hppa/machine.c
@@ -366,12 +366,15 @@ static void machine_HP_common_init_tail(MachineState *machine, PCIBus *pci_bus,
/* Graphics setup. */
if (machine->enable_graphics && vga_interface_type != VGA_NONE) {
- vga_interface_created = true;
dev = qdev_new("artist");
s = SYS_BUS_DEVICE(dev);
- sysbus_realize_and_unref(s, &error_fatal);
- sysbus_mmio_map(s, 0, translate(NULL, LASI_GFX_HPA));
- sysbus_mmio_map(s, 1, translate(NULL, ARTIST_FB_ADDR));
+ bool disabled = object_property_get_bool(OBJECT(dev), "disable", NULL);
+ if (!disabled) {
+ sysbus_realize_and_unref(s, &error_fatal);
+ vga_interface_created = true;
+ sysbus_mmio_map(s, 0, translate(NULL, LASI_GFX_HPA));
+ sysbus_mmio_map(s, 1, translate(NULL, ARTIST_FB_ADDR));
+ }
}
/* Network setup. */
@@ -383,26 +386,17 @@ static void machine_HP_common_init_tail(MachineState *machine, PCIBus *pci_bus,
pci_init_nic_devices(pci_bus, mc->default_nic);
- /* BMC board: HP Powerbar SP2 Diva (with console only) */
- pci_dev = pci_new(-1, "pci-serial");
- if (!lasi_dev) {
- /* bind default keyboard/serial to Diva card */
- qdev_prop_set_chr(DEVICE(pci_dev), "chardev", serial_hd(0));
- }
- qdev_prop_set_uint8(DEVICE(pci_dev), "prog_if", 0);
- pci_realize_and_unref(pci_dev, pci_bus, &error_fatal);
- pci_config_set_vendor_id(pci_dev->config, PCI_VENDOR_ID_HP);
- pci_config_set_device_id(pci_dev->config, 0x1048);
- pci_set_word(&pci_dev->config[PCI_SUBSYSTEM_VENDOR_ID], PCI_VENDOR_ID_HP);
- pci_set_word(&pci_dev->config[PCI_SUBSYSTEM_ID], 0x1227); /* Powerbar */
-
- /* create a second serial PCI card when running Astro */
- if (serial_hd(1) && !lasi_dev) {
- pci_dev = pci_new(-1, "pci-serial-4x");
- qdev_prop_set_chr(DEVICE(pci_dev), "chardev1", serial_hd(1));
- qdev_prop_set_chr(DEVICE(pci_dev), "chardev2", serial_hd(2));
- qdev_prop_set_chr(DEVICE(pci_dev), "chardev3", serial_hd(3));
- qdev_prop_set_chr(DEVICE(pci_dev), "chardev4", serial_hd(4));
+ /* BMC board: HP Diva GSP */
+ dev = qdev_new("diva-gsp");
+ if (!object_property_get_bool(OBJECT(dev), "disable", NULL)) {
+ pci_dev = pci_new_multifunction(PCI_DEVFN(2, 0), "diva-gsp");
+ if (!lasi_dev) {
+ /* bind default keyboard/serial to Diva card */
+ qdev_prop_set_chr(DEVICE(pci_dev), "chardev1", serial_hd(0));
+ qdev_prop_set_chr(DEVICE(pci_dev), "chardev2", serial_hd(1));
+ qdev_prop_set_chr(DEVICE(pci_dev), "chardev3", serial_hd(2));
+ qdev_prop_set_chr(DEVICE(pci_dev), "chardev4", serial_hd(3));
+ }
pci_realize_and_unref(pci_dev, pci_bus, &error_fatal);
}
diff --git a/hw/pci-host/astro.c b/hw/pci-host/astro.c
index 62e9c8a..039cc3a 100644
--- a/hw/pci-host/astro.c
+++ b/hw/pci-host/astro.c
@@ -521,6 +521,53 @@ static ElroyState *elroy_init(int num)
* Astro Runway chip.
*/
+static void adjust_LMMIO_DIRECT_mapping(AstroState *s, unsigned int reg_index)
+{
+ MemoryRegion *lmmio_alias;
+ unsigned int lmmio_index, map_route;
+ hwaddr map_addr;
+ uint32_t map_size;
+ struct ElroyState *elroy;
+
+ /* pointer to LMMIO_DIRECT entry */
+ lmmio_index = reg_index / 3;
+ lmmio_alias = &s->lmmio_direct[lmmio_index];
+
+ map_addr = s->ioc_ranges[3 * lmmio_index + 0];
+ map_size = s->ioc_ranges[3 * lmmio_index + 1];
+ map_route = s->ioc_ranges[3 * lmmio_index + 2];
+
+ /* find elroy to which this address is routed */
+ map_route &= (ELROY_NUM - 1);
+ elroy = s->elroy[map_route];
+
+ if (lmmio_alias->enabled) {
+ memory_region_set_enabled(lmmio_alias, false);
+ }
+
+ map_addr = F_EXTEND(map_addr);
+ map_addr &= TARGET_PAGE_MASK;
+ map_size = (~map_size) + 1;
+ map_size &= TARGET_PAGE_MASK;
+
+ /* exit if disabled or zero map size */
+ if (!(map_addr & 1) || !map_size) {
+ return;
+ }
+
+ if (!memory_region_size(lmmio_alias)) {
+ memory_region_init_alias(lmmio_alias, OBJECT(elroy),
+ "pci-lmmmio-alias", &elroy->pci_mmio,
+ (uint32_t) map_addr, map_size);
+ memory_region_add_subregion(get_system_memory(), map_addr,
+ lmmio_alias);
+ } else {
+ memory_region_set_alias_offset(lmmio_alias, map_addr);
+ memory_region_set_size(lmmio_alias, map_size);
+ memory_region_set_enabled(lmmio_alias, true);
+ }
+}
+
static MemTxResult astro_chip_read_with_attrs(void *opaque, hwaddr addr,
uint64_t *data, unsigned size,
MemTxAttrs attrs)
@@ -628,6 +675,11 @@ static MemTxResult astro_chip_write_with_attrs(void *opaque, hwaddr addr,
break;
case 0x0300 ... 0x03d8 - 1: /* LMMIO_DIRECT0_BASE... */
put_val_in_arrary(s->ioc_ranges, 0x300, addr, size, val);
+ unsigned int index = (addr - 0x300) / 8;
+ /* check if one of the 4 LMMIO_DIRECT regs, each using 3 entries. */
+ if (index < LMMIO_DIRECT_RANGES * 3) {
+ adjust_LMMIO_DIRECT_mapping(s, index);
+ }
break;
case 0x10200:
case 0x10220:
diff --git a/include/hw/pci-host/astro.h b/include/hw/pci-host/astro.h
index e296691..832125a 100644
--- a/include/hw/pci-host/astro.h
+++ b/include/hw/pci-host/astro.h
@@ -24,6 +24,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(ElroyState, ELROY_PCI_HOST_BRIDGE)
#define LMMIO_DIST_BASE_ADDR 0xf4000000ULL
#define LMMIO_DIST_BASE_SIZE 0x4000000ULL
+#define LMMIO_DIRECT_RANGES 4
+
#define IOS_DIST_BASE_ADDR 0xfffee00000ULL
#define IOS_DIST_BASE_SIZE 0x10000ULL
@@ -83,9 +85,7 @@ struct AstroState {
struct ElroyState *elroy[ELROY_NUM];
MemoryRegion this_mem;
-
- MemoryRegion pci_mmio;
- MemoryRegion pci_io;
+ MemoryRegion lmmio_direct[LMMIO_DIRECT_RANGES];
IOMMUMemoryRegion iommu;
AddressSpace iommu_as;
diff --git a/roms/seabios-hppa b/roms/seabios-hppa
-Subproject 1c516b481339f511d83a4afba9a48d1ac904e93
+Subproject 3391c580960febcb9fa8f686f9666adaa462c34