mirror of
https://github.com/qemu/qemu.git
synced 2025-08-13 18:46:38 +00:00
HPPA graphics and serial console enhancements
A small series of patches which enhance the graphics output on 64-bit hppa machines. Allow disabling the artist graphic card and introduces drivers for the Diva GSP (remote management) cards which are used in later 64-bit machines and which we now use for serial console output. The LMMIO regions of the Astro chip are now supported too, which is important to support other graphic cards like an ATI PCI card with a 64-bit Linux kernel. -----BEGIN PGP SIGNATURE----- iHUEABYKAB0WIQS86RI+GtKfB8BJu973ErUQojoPXwUCZ6Z1YQAKCRD3ErUQojoP X+LvAP0dXGZDtE9Lj5SWuZZVLd/g/KIqx7cvGcRFQSnmAEvqSAD/SIUmCzjxrHfD KOUS+DVaCd7xvSIEJtzch2zBL5jvuAw= =H3Wz -----END PGP SIGNATURE----- Merge tag 'hppa-system-for-v10-diva-artist-pull-request' of https://github.com/hdeller/qemu-hppa into staging HPPA graphics and serial console enhancements A small series of patches which enhance the graphics output on 64-bit hppa machines. Allow disabling the artist graphic card and introduces drivers for the Diva GSP (remote management) cards which are used in later 64-bit machines and which we now use for serial console output. The LMMIO regions of the Astro chip are now supported too, which is important to support other graphic cards like an ATI PCI card with a 64-bit Linux kernel. # -----BEGIN PGP SIGNATURE----- # # iHUEABYKAB0WIQS86RI+GtKfB8BJu973ErUQojoPXwUCZ6Z1YQAKCRD3ErUQojoP # X+LvAP0dXGZDtE9Lj5SWuZZVLd/g/KIqx7cvGcRFQSnmAEvqSAD/SIUmCzjxrHfD # KOUS+DVaCd7xvSIEJtzch2zBL5jvuAw= # =H3Wz # -----END PGP SIGNATURE----- # gpg: Signature made Fri 07 Feb 2025 16:04:33 EST # gpg: using EDDSA key BCE9123E1AD29F07C049BBDEF712B510A23A0F5F # gpg: Good signature from "Helge Deller <deller@gmx.de>" [unknown] # gpg: aka "Helge Deller <deller@kernel.org>" [unknown] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 4544 8228 2CD9 10DB EF3D 25F8 3E5F 3D04 A7A2 4603 # Subkey fingerprint: BCE9 123E 1AD2 9F07 C049 BBDE F712 B510 A23A 0F5F * tag 'hppa-system-for-v10-diva-artist-pull-request' of https://github.com/hdeller/qemu-hppa: target/hppa: Update SeaBIOS-hppa hw/pci-host/astro: Add LMMIO range support hw/hppa: Avoid creation of artist if disabled on command line artist: Allow disabling artist on command line hw/hppa: Wire up Diva GSP card hw/char: Add emulation of Diva GSP PCI management boards Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
commit
04d3d0e9f5
@ -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
|
||||
|
@ -66,6 +66,9 @@ config RENESAS_SCI
|
||||
config AVR_USART
|
||||
bool
|
||||
|
||||
config DIVA_GSP
|
||||
bool
|
||||
|
||||
config MCHP_PFSOC_MMUART
|
||||
bool
|
||||
select SERIAL
|
||||
|
297
hw/char/diva-gsp.c
Normal file
297
hw/char/diva-gsp.c
Normal file
@ -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)
|
@ -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'))
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 1c516b481339f511d83a4afba9a48d1ac904e93e
|
||||
Subproject commit 3391c580960febcb9fa8f686f9666adaa462c349
|
Loading…
Reference in New Issue
Block a user