@@ -1,5 +1,12 @@
config LOONGSON3_LS7A
bool
+ imply VGA_PCI
+ imply VIRTIO_VGA
+ imply PCI_DEVICES
+ select ISA_BUS
+ select SERIAL
+ select SERIAL_ISA
+ select VIRTIO_PCI
select PCI_EXPRESS_7A
select LOONGARCH_IPI
select LOONGARCH_PCH_PIC
@@ -10,16 +10,20 @@
#include "qemu/datadir.h"
#include "qapi/error.h"
#include "hw/boards.h"
+#include "hw/char/serial.h"
#include "sysemu/sysemu.h"
#include "sysemu/qtest.h"
#include "sysemu/runstate.h"
#include "sysemu/reset.h"
+#include "hw/irq.h"
+#include "net/net.h"
#include "hw/loongarch/loongarch.h"
#include "hw/intc/loongarch_ipi.h"
#include "hw/intc/loongarch_extioi.h"
#include "hw/intc/loongarch_pch_pic.h"
#include "hw/intc/loongarch_pch_msi.h"
#include "hw/pci-host/ls7a.h"
+#include "hw/misc/unimp.h"
static void loongarch_cpu_reset(void *opaque)
{
@@ -97,6 +101,70 @@ static void loongarch_cpu_set_irq(void *opaque, int irq, int level)
}
}
+static void loongarch_devices_init(DeviceState *pch_pic)
+{
+ DeviceState *pciehost;
+ SysBusDevice *d;
+ PCIBus *pci_bus;
+ MemoryRegion *pio_alias;
+ int i;
+
+ pciehost = qdev_new(TYPE_LS7A_HOST_DEVICE);
+ d = SYS_BUS_DEVICE(pciehost);
+ sysbus_realize_and_unref(d, &error_fatal);
+ pci_bus = PCI_HOST_BRIDGE(pciehost)->bus;
+
+ /* Map pcie ecam space */
+ memory_region_add_subregion(get_system_memory(), LS_PCIECFG_BASE,
+ sysbus_mmio_get_region(d, 0));
+
+ /* Map PCI IO port space. */
+ pio_alias = g_new0(MemoryRegion, 1);
+ memory_region_init_alias(pio_alias, OBJECT(pciehost), "ls7a-pci-io",
+ sysbus_mmio_get_region(d, 1),
+ LS7A_PCI_IO_OFFSET, LS7A_PCI_IO_SIZE);
+ memory_region_add_subregion(get_system_memory(), LS7A_PCI_IO_BASE,
+ pio_alias);
+
+ /* Map PCI mem space */
+ memory_region_add_subregion(get_system_memory(), 0,
+ sysbus_mmio_get_region(d, 2));
+
+ /* Map PCI conf space */
+ memory_region_add_subregion(get_system_memory(), HT1LO_PCICFG_BASE,
+ sysbus_mmio_get_region(d, 3));
+
+ /* Connect 48 pci irqs to pch_pic */
+ for (i = 0; i < LS7A_PCI_IRQS; i++) {
+ qdev_connect_gpio_out(pciehost, i,
+ qdev_get_gpio_in(pch_pic, i + LS7A_DEVICE_IRQS));
+ }
+
+ serial_mm_init(get_system_memory(), LS7A_UART_BASE, 0,
+ qdev_get_gpio_in(pch_pic, LS7A_UART_IRQ - PCH_PIC_IRQ_OFFSET),
+ 115200, serial_hd(0), DEVICE_LITTLE_ENDIAN);
+
+ /* Network init */
+ for (i = 0; i < nb_nics; i++) {
+ NICInfo *nd = &nd_table[i];
+
+ if (!nd->model) {
+ nd->model = g_strdup("virtio");
+ }
+
+ pci_nic_init_nofail(nd, pci_bus, nd->model, NULL);
+ }
+
+ /* VGA setup */
+ pci_vga_init(pci_bus);
+
+ /*
+ * There are some invalid guest memory access.
+ * Create some unimplemented devices to emulate this.
+ */
+ create_unimplemented_device("pci-dma-cfg", 0x1001041c, 0x4);
+}
+
static void loongarch_irq_init(LoongArchMachineState *lams)
{
MachineState *ms = MACHINE(lams);
@@ -173,6 +241,8 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
sysbus_connect_irq(d, i,
qdev_get_gpio_in(extioi, i + PCH_MSI_IRQ_START));
}
+
+ loongarch_devices_init(pch_pic);
}
static void loongarch_init(MachineState *machine)
@@ -28,6 +28,41 @@ static const VMStateDescription vmstate_ls7a_pcie = {
}
};
+static PCIINTxRoute ls7a_route_intx_pin_to_irq(void *opaque, int pin)
+{
+ PCIINTxRoute route;
+
+ route.irq = pin;
+ route.mode = PCI_INTX_ENABLED;
+ return route;
+}
+
+static int pci_ls7a_map_irq(PCIDevice *d, int irq_num)
+{
+ PCIBus *bus;
+ int offset, irq;
+
+ bus = pci_get_bus(d);
+ if (bus->parent_dev) {
+ irq = pci_swizzle_map_irq_fn(d, irq_num);
+ return irq;
+ }
+
+ /* pci device start from irq 80 */
+ offset = PCH_PIC_IRQ_OFFSET + LS7A_DEVICE_IRQS;
+ irq = offset + ((PCI_SLOT(d->devfn) * 4 + irq_num)) % LS7A_PCI_IRQS;
+
+ return irq;
+}
+
+static void pci_ls7a_set_irq(void *opaque, int irq_num, int level)
+{
+ LS7APCIEHost *pciehost = opaque;
+ int offset = PCH_PIC_IRQ_OFFSET + LS7A_DEVICE_IRQS;
+
+ qemu_set_irq(pciehost->irqs[irq_num - offset], level);
+}
+
static void pci_ls7a_config_write(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
@@ -74,10 +109,13 @@ static void ls7a_pciehost_realize(DeviceState *dev, Error **errp)
sysbus_init_mmio(sbd, &s->pci_io);
sysbus_init_mmio(sbd, &s->pci_mmio);
- pci->bus = pci_register_root_bus(dev, "pcie.0", NULL, NULL, s,
+ pci->bus = pci_register_root_bus(dev, "pcie.0", pci_ls7a_set_irq,
+ pci_ls7a_map_irq, s,
&s->pci_mmio, &s->pci_io,
PCI_DEVFN(1, 0), 128, TYPE_PCIE_BUS);
+ pci_bus_set_route_irq_fn(pci->bus, ls7a_route_intx_pin_to_irq);
+
memory_region_init_io(&s->pci_conf, OBJECT(dev),
&pci_ls7a_config_ops, pci->bus,
"ls7a_pci_conf", HT1LO_PCICFG_SIZE);
@@ -141,6 +179,8 @@ static void ls7a_pciehost_initfn(Object *obj)
object_initialize_child(obj, "ls7a_pci", ls7a_pci, TYPE_LS7A_PCI_DEVICE);
qdev_prop_set_int32(DEVICE(ls7a_pci), "addr", PCI_DEVFN(0, 0));
qdev_prop_set_bit(DEVICE(ls7a_pci), "multifunction", false);
+
+ qdev_init_gpio_out(DEVICE(obj), s->irqs, LS7A_PCI_IRQS);
}
static const char *ls7a_pciehost_root_bus_path(PCIHostState *host_bridge,
@@ -23,6 +23,7 @@
#define LS7A_PCI_IO_BASE 0x18004000UL
#define LS7A_PCI_IO_SIZE 0xC000
+#define LS7A_PCI_IO_OFFSET 0x4000
#define LS7A_PCH_REG_BASE 0x10000000UL
#define LS7A_IOAPIC_REG_BASE (LS7A_PCH_REG_BASE)
@@ -37,6 +38,9 @@
#define LS7A_DEVICE_IRQS 16
#define LS7A_PCI_IRQS 48
+#define LS7A_UART_IRQ (PCH_PIC_IRQ_OFFSET + 2)
+#define LS7A_UART_BASE 0x1fe001e0
+
struct LS7APCIState {
/*< private >*/
PCIDevice parent_obj;
@@ -51,6 +55,7 @@ typedef struct LS7APCIEHost {
LS7APCIState pci_dev;
+ qemu_irq irqs[LS7A_PCI_IRQS];
MemoryRegion pci_conf;
MemoryRegion pci_mmio;
MemoryRegion pci_io;