SCU_HW_STRAP_VGA_SIZE_SET(VGA_64M_DRAM) | \
SCU_AST2500_HW_STRAP_RESERVED1)
+/* FP5280G2 hardware value: 0XF100D286 */
+#define FP5280G2_BMC_HW_STRAP1 ( \
+ SCU_AST2500_HW_STRAP_SPI_AUTOFETCH_ENABLE | \
+ SCU_AST2500_HW_STRAP_GPIO_STRAP_ENABLE | \
+ SCU_AST2500_HW_STRAP_UART_DEBUG | \
+ SCU_AST2500_HW_STRAP_RESERVED28 | \
+ SCU_AST2500_HW_STRAP_DDR4_ENABLE | \
+ SCU_HW_STRAP_VGA_CLASS_CODE | \
+ SCU_HW_STRAP_LPC_RESET_PIN | \
+ SCU_HW_STRAP_SPI_MODE(SCU_HW_STRAP_SPI_MASTER) | \
+ SCU_AST2500_HW_STRAP_SET_AXI_AHB_RATIO(AXI_AHB_RATIO_2_1) | \
+ SCU_HW_STRAP_MAC1_RGMII | \
+ SCU_HW_STRAP_VGA_SIZE_SET(VGA_16M_DRAM) | \
+ SCU_AST2500_HW_STRAP_RESERVED1)
+
/* Witherspoon hardware value: 0xF10AD216 (but use romulus definition) */
#define WITHERSPOON_BMC_HW_STRAP1 ROMULUS_BMC_HW_STRAP1
arm_load_kernel(ARM_CPU(first_cpu), machine, &aspeed_board_binfo);
}
+static void at24c_eeprom_init(I2CBus *bus, uint8_t addr, uint32_t rsize)
+{
+ I2CSlave *i2c_dev = i2c_slave_new("at24c-eeprom", addr);
+ DeviceState *dev = DEVICE(i2c_dev);
+
+ qdev_prop_set_uint32(dev, "rom-size", rsize);
+ i2c_slave_realize_and_unref(i2c_dev, bus, &error_abort);
+}
+
static void palmetto_bmc_i2c_init(AspeedMachineState *bmc)
{
AspeedSoCState *soc = &bmc->soc;
i2c_slave_realize_and_unref(i2c_dev, bus, &error_abort);
}
+static void fp5280g2_bmc_i2c_init(AspeedMachineState *bmc)
+{
+ AspeedSoCState *soc = &bmc->soc;
+ I2CSlave *i2c_mux;
+
+ /* The at24c256 */
+ at24c_eeprom_init(aspeed_i2c_get_bus(&soc->i2c, 1), 0x50, 32768);
+
+ /* The fp5280g2 expects a TMP112 but a TMP105 is compatible */
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 2), TYPE_TMP105,
+ 0x48);
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 2), TYPE_TMP105,
+ 0x49);
+
+ i2c_mux = i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 2),
+ "pca9546", 0x70);
+ /* It expects a TMP112 but a TMP105 is compatible */
+ i2c_slave_create_simple(pca954x_i2c_get_bus(i2c_mux, 0), TYPE_TMP105,
+ 0x4a);
+
+ /* It expects a ds3232 but a ds1338 is good enough */
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 4), "ds1338", 0x68);
+
+ /* It expects a pca9555 but a pca9552 is compatible */
+ i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 8), TYPE_PCA9552,
+ 0x20);
+}
+
static void rainier_bmc_i2c_init(AspeedMachineState *bmc)
{
AspeedSoCState *soc = &bmc->soc;
aspeed_soc_num_cpus(amc->soc_name);
};
+static void aspeed_machine_fp5280g2_class_init(ObjectClass *oc, void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+ AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
+
+ mc->desc = "Inspur FP5280G2 BMC (ARM1176)";
+ amc->soc_name = "ast2500-a1";
+ amc->hw_strap1 = FP5280G2_BMC_HW_STRAP1;
+ amc->fmc_model = "n25q512a";
+ amc->spi_model = "mx25l25635e";
+ amc->num_cs = 2;
+ amc->macs_mask = ASPEED_MAC0_ON | ASPEED_MAC1_ON;
+ amc->i2c_init = fp5280g2_bmc_i2c_init;
+ mc->default_ram_size = 512 * MiB;
+ mc->default_cpus = mc->min_cpus = mc->max_cpus =
+ aspeed_soc_num_cpus(amc->soc_name);
+};
+
static void aspeed_machine_rainier_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
.parent = TYPE_ASPEED_MACHINE,
.class_init = aspeed_machine_g220a_class_init,
}, {
+ .name = MACHINE_TYPE_NAME("fp5280g2-bmc"),
+ .parent = TYPE_ASPEED_MACHINE,
+ .class_init = aspeed_machine_fp5280g2_class_init,
+ }, {
.name = MACHINE_TYPE_NAME("quanta-q71l-bmc"),
.parent = TYPE_ASPEED_MACHINE,
.class_init = aspeed_machine_quanta_q71l_class_init,
#include "cpu.h"
#include "hw/boards.h"
#include "hw/or-irq.h"
+#include "hw/nmi.h"
#include "elf.h"
#include "hw/loader.h"
#include "ui/console.h"
SysBusDevice parent_obj;
M68kCPU *cpu;
uint8_t ipr;
+ uint8_t auxmode;
+ qemu_irq irqs[1];
+ QEMUTimer *nmi_release;
};
+#define GLUE_IRQ_IN_VIA1 0
+#define GLUE_IRQ_IN_VIA2 1
+#define GLUE_IRQ_IN_SONIC 2
+#define GLUE_IRQ_IN_ESCC 3
+#define GLUE_IRQ_IN_NMI 4
+
+#define GLUE_IRQ_NUBUS_9 0
+
+/*
+ * The GLUE logic on the Quadra 800 supports 2 different IRQ routing modes
+ * controlled from the VIA1 auxmode GPIO (port B bit 6) which are documented
+ * in NetBSD as follows:
+ *
+ * A/UX mode (Linux, NetBSD, auxmode GPIO low)
+ *
+ * Level 0: Spurious: ignored
+ * Level 1: Software
+ * Level 2: VIA2 (except ethernet, sound)
+ * Level 3: Ethernet
+ * Level 4: Serial (SCC)
+ * Level 5: Sound
+ * Level 6: VIA1
+ * Level 7: NMIs: parity errors, RESET button, YANCC error
+ *
+ * Classic mode (default: used by MacOS, A/UX 3.0.1, auxmode GPIO high)
+ *
+ * Level 0: Spurious: ignored
+ * Level 1: VIA1 (clock, ADB)
+ * Level 2: VIA2 (NuBus, SCSI)
+ * Level 3:
+ * Level 4: Serial (SCC)
+ * Level 5:
+ * Level 6:
+ * Level 7: Non-maskable: parity errors, RESET button
+ *
+ * Note that despite references to A/UX mode in Linux and NetBSD, at least
+ * A/UX 3.0.1 still uses Classic mode.
+ */
+
static void GLUE_set_irq(void *opaque, int irq, int level)
{
GLUEState *s = opaque;
int i;
+ if (s->auxmode) {
+ /* Classic mode */
+ switch (irq) {
+ case GLUE_IRQ_IN_VIA1:
+ irq = 0;
+ break;
+
+ case GLUE_IRQ_IN_VIA2:
+ irq = 1;
+ break;
+
+ case GLUE_IRQ_IN_SONIC:
+ /* Route to VIA2 instead */
+ qemu_set_irq(s->irqs[GLUE_IRQ_NUBUS_9], level);
+ return;
+
+ case GLUE_IRQ_IN_ESCC:
+ irq = 3;
+ break;
+
+ case GLUE_IRQ_IN_NMI:
+ irq = 6;
+ break;
+
+ default:
+ g_assert_not_reached();
+ }
+ } else {
+ /* A/UX mode */
+ switch (irq) {
+ case GLUE_IRQ_IN_VIA1:
+ irq = 5;
+ break;
+
+ case GLUE_IRQ_IN_VIA2:
+ irq = 1;
+ break;
+
+ case GLUE_IRQ_IN_SONIC:
+ irq = 2;
+ break;
+
+ case GLUE_IRQ_IN_ESCC:
+ irq = 3;
+ break;
+
+ case GLUE_IRQ_IN_NMI:
+ irq = 6;
+ break;
+
+ default:
+ g_assert_not_reached();
+ }
+ }
+
if (level) {
s->ipr |= 1 << irq;
} else {
m68k_set_irq_level(s->cpu, 0, 0);
}
+static void glue_auxmode_set_irq(void *opaque, int irq, int level)
+{
+ GLUEState *s = GLUE(opaque);
+
+ s->auxmode = level;
+}
+
+static void glue_nmi(NMIState *n, int cpu_index, Error **errp)
+{
+ GLUEState *s = GLUE(n);
+
+ /* Hold NMI active for 100ms */
+ GLUE_set_irq(s, GLUE_IRQ_IN_NMI, 1);
+ timer_mod(s->nmi_release, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 100);
+}
+
+static void glue_nmi_release(void *opaque)
+{
+ GLUEState *s = GLUE(opaque);
+
+ GLUE_set_irq(s, GLUE_IRQ_IN_NMI, 0);
+}
+
static void glue_reset(DeviceState *dev)
{
GLUEState *s = GLUE(dev);
s->ipr = 0;
+ s->auxmode = 0;
+
+ timer_del(s->nmi_release);
}
static const VMStateDescription vmstate_glue = {
.minimum_version_id = 0,
.fields = (VMStateField[]) {
VMSTATE_UINT8(ipr, GLUEState),
+ VMSTATE_UINT8(auxmode, GLUEState),
+ VMSTATE_TIMER_PTR(nmi_release, GLUEState),
VMSTATE_END_OF_LIST(),
},
};
DEFINE_PROP_END_OF_LIST(),
};
+static void glue_finalize(Object *obj)
+{
+ GLUEState *s = GLUE(obj);
+
+ timer_free(s->nmi_release);
+}
+
static void glue_init(Object *obj)
{
DeviceState *dev = DEVICE(obj);
+ GLUEState *s = GLUE(dev);
qdev_init_gpio_in(dev, GLUE_set_irq, 8);
+ qdev_init_gpio_in_named(dev, glue_auxmode_set_irq, "auxmode", 1);
+
+ qdev_init_gpio_out(dev, s->irqs, 1);
+
+ /* NMI release timer */
+ s->nmi_release = timer_new_ms(QEMU_CLOCK_VIRTUAL, glue_nmi_release, s);
}
static void glue_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
+ NMIClass *nc = NMI_CLASS(klass);
dc->vmsd = &vmstate_glue;
dc->reset = glue_reset;
device_class_set_props(dc, glue_properties);
+ nc->nmi_monitor_handler = glue_nmi;
}
static const TypeInfo glue_info = {
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(GLUEState),
.instance_init = glue_init,
+ .instance_finalize = glue_finalize,
.class_init = glue_class_init,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_NMI },
+ { }
+ },
};
static void main_cpu_reset(void *opaque)
sysbus = SYS_BUS_DEVICE(via1_dev);
sysbus_realize_and_unref(sysbus, &error_fatal);
sysbus_mmio_map(sysbus, 1, VIA_BASE);
- sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(glue, 0));
+ sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(glue, GLUE_IRQ_IN_VIA1));
+ /* A/UX mode */
+ qdev_connect_gpio_out(via1_dev, 0,
+ qdev_get_gpio_in_named(glue, "auxmode", 0));
adb_bus = qdev_get_child_bus(via1_dev, "adb.0");
dev = qdev_new(TYPE_ADB_KEYBOARD);
sysbus = SYS_BUS_DEVICE(via2_dev);
sysbus_realize_and_unref(sysbus, &error_fatal);
sysbus_mmio_map(sysbus, 1, VIA_BASE + VIA_SIZE);
- sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(glue, 1));
+ sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(glue, GLUE_IRQ_IN_VIA2));
/* MACSONIC */
sysbus = SYS_BUS_DEVICE(dev);
sysbus_realize_and_unref(sysbus, &error_fatal);
sysbus_mmio_map(sysbus, 0, SONIC_BASE);
- sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(glue, 2));
+ sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(glue, GLUE_IRQ_IN_SONIC));
memory_region_init_rom(dp8393x_prom, NULL, "dp8393x-q800.prom",
SONIC_PROM_SIZE, &error_fatal);
qdev_realize_and_unref(escc_orgate, NULL, &error_fatal);
sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(escc_orgate, 0));
sysbus_connect_irq(sysbus, 1, qdev_get_gpio_in(escc_orgate, 1));
- qdev_connect_gpio_out(DEVICE(escc_orgate), 0, qdev_get_gpio_in(glue, 3));
+ qdev_connect_gpio_out(DEVICE(escc_orgate), 0,
+ qdev_get_gpio_in(glue, GLUE_IRQ_IN_ESCC));
sysbus_mmio_map(sysbus, 0, SCC_BASE);
/* SCSI */
VIA2_NUBUS_IRQ_9 + i));
}
+ /*
+ * Since the framebuffer in slot 0x9 uses a separate IRQ, wire the unused
+ * IRQ via GLUE for use by SONIC Ethernet in classic mode
+ */
+ qdev_connect_gpio_out(glue, GLUE_IRQ_NUBUS_9,
+ qdev_get_gpio_in_named(via2_dev, "nubus-irq",
+ VIA2_NUBUS_IRQ_9));
+
nubus = &NUBUS_BRIDGE(dev)->bus;
/* framebuffer in nubus slot #9 */
qdev_prop_set_uint32(dev, "width", graphic_width);
qdev_prop_set_uint32(dev, "height", graphic_height);
qdev_prop_set_uint8(dev, "depth", graphic_depth);
- if (graphic_width == 1152 && graphic_height == 870 && graphic_depth == 8) {
+ if (graphic_width == 1152 && graphic_height == 870) {
qdev_prop_set_uint8(dev, "display", MACFB_DISPLAY_APPLE_21_COLOR);
} else {
qdev_prop_set_uint8(dev, "display", MACFB_DISPLAY_VGA);