hw/intc: Add LoongArch ls7a interrupt controller support(PCH-PIC)
This patch realize the PCH-PIC interrupt controller. Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn> Signed-off-by: Song Gao <gaosong@loongson.cn> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-Id: <20220606124333.2060567-33-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
parent
f6783e3438
commit
0f4fcf1845
@ -1135,6 +1135,7 @@ F: hw/loongarch/
|
||||
F: include/hw/loongarch/virt.h
|
||||
F: include/hw/intc/loongarch_*.h
|
||||
F: hw/intc/loongarch_*.c
|
||||
F: include/hw/pci-host/ls7a.h
|
||||
|
||||
M68K Machines
|
||||
-------------
|
||||
|
@ -90,3 +90,7 @@ config NIOS2_VIC
|
||||
|
||||
config LOONGARCH_IPI
|
||||
bool
|
||||
|
||||
config LOONGARCH_PCH_PIC
|
||||
bool
|
||||
select UNIMP
|
||||
|
431
hw/intc/loongarch_pch_pic.c
Normal file
431
hw/intc/loongarch_pch_pic.c
Normal file
@ -0,0 +1,431 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* QEMU Loongson 7A1000 I/O interrupt controller.
|
||||
*
|
||||
* Copyright (C) 2021 Loongson Technology Corporation Limited
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/loongarch/virt.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/intc/loongarch_pch_pic.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "trace.h"
|
||||
|
||||
static void pch_pic_update_irq(LoongArchPCHPIC *s, uint64_t mask, int level)
|
||||
{
|
||||
unsigned long val;
|
||||
int irq;
|
||||
|
||||
if (level) {
|
||||
val = mask & s->intirr & ~s->int_mask;
|
||||
if (val) {
|
||||
irq = find_first_bit(&val, 64);
|
||||
s->intisr |= 0x1ULL << irq;
|
||||
qemu_set_irq(s->parent_irq[s->htmsi_vector[irq]], 1);
|
||||
}
|
||||
} else {
|
||||
val = mask & s->intisr;
|
||||
if (val) {
|
||||
irq = find_first_bit(&val, 64);
|
||||
s->intisr &= ~(0x1ULL << irq);
|
||||
qemu_set_irq(s->parent_irq[s->htmsi_vector[irq]], 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void pch_pic_irq_handler(void *opaque, int irq, int level)
|
||||
{
|
||||
LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
|
||||
uint64_t mask = 1ULL << irq;
|
||||
|
||||
assert(irq < PCH_PIC_IRQ_NUM);
|
||||
trace_loongarch_pch_pic_irq_handler(irq, level);
|
||||
|
||||
if (s->intedge & mask) {
|
||||
/* Edge triggered */
|
||||
if (level) {
|
||||
if ((s->last_intirr & mask) == 0) {
|
||||
s->intirr |= mask;
|
||||
}
|
||||
s->last_intirr |= mask;
|
||||
} else {
|
||||
s->last_intirr &= ~mask;
|
||||
}
|
||||
} else {
|
||||
/* Level triggered */
|
||||
if (level) {
|
||||
s->intirr |= mask;
|
||||
s->last_intirr |= mask;
|
||||
} else {
|
||||
s->intirr &= ~mask;
|
||||
s->last_intirr &= ~mask;
|
||||
}
|
||||
}
|
||||
pch_pic_update_irq(s, mask, level);
|
||||
}
|
||||
|
||||
static uint64_t loongarch_pch_pic_low_readw(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
|
||||
uint64_t val = 0;
|
||||
uint32_t offset = addr & 0xfff;
|
||||
|
||||
switch (offset) {
|
||||
case PCH_PIC_INT_ID_LO:
|
||||
val = PCH_PIC_INT_ID_VAL;
|
||||
break;
|
||||
case PCH_PIC_INT_ID_HI:
|
||||
val = PCH_PIC_INT_ID_NUM;
|
||||
break;
|
||||
case PCH_PIC_INT_MASK_LO:
|
||||
val = (uint32_t)s->int_mask;
|
||||
break;
|
||||
case PCH_PIC_INT_MASK_HI:
|
||||
val = s->int_mask >> 32;
|
||||
break;
|
||||
case PCH_PIC_INT_EDGE_LO:
|
||||
val = (uint32_t)s->intedge;
|
||||
break;
|
||||
case PCH_PIC_INT_EDGE_HI:
|
||||
val = s->intedge >> 32;
|
||||
break;
|
||||
case PCH_PIC_HTMSI_EN_LO:
|
||||
val = (uint32_t)s->htmsi_en;
|
||||
break;
|
||||
case PCH_PIC_HTMSI_EN_HI:
|
||||
val = s->htmsi_en >> 32;
|
||||
break;
|
||||
case PCH_PIC_AUTO_CTRL0_LO:
|
||||
case PCH_PIC_AUTO_CTRL0_HI:
|
||||
case PCH_PIC_AUTO_CTRL1_LO:
|
||||
case PCH_PIC_AUTO_CTRL1_HI:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
trace_loongarch_pch_pic_low_readw(size, addr, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
static uint64_t get_writew_val(uint64_t value, uint32_t target, bool hi)
|
||||
{
|
||||
uint64_t mask = 0xffffffff00000000;
|
||||
uint64_t data = target;
|
||||
|
||||
return hi ? (value & ~mask) | (data << 32) : (value & mask) | data;
|
||||
}
|
||||
|
||||
static void loongarch_pch_pic_low_writew(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
|
||||
uint32_t offset, old_valid, data = (uint32_t)value;
|
||||
uint64_t old, int_mask;
|
||||
offset = addr & 0xfff;
|
||||
|
||||
trace_loongarch_pch_pic_low_writew(size, addr, data);
|
||||
|
||||
switch (offset) {
|
||||
case PCH_PIC_INT_MASK_LO:
|
||||
old = s->int_mask;
|
||||
s->int_mask = get_writew_val(old, data, 0);
|
||||
old_valid = (uint32_t)old;
|
||||
if (old_valid & ~data) {
|
||||
pch_pic_update_irq(s, (old_valid & ~data), 1);
|
||||
}
|
||||
if (~old_valid & data) {
|
||||
pch_pic_update_irq(s, (~old_valid & data), 0);
|
||||
}
|
||||
break;
|
||||
case PCH_PIC_INT_MASK_HI:
|
||||
old = s->int_mask;
|
||||
s->int_mask = get_writew_val(old, data, 1);
|
||||
old_valid = (uint32_t)(old >> 32);
|
||||
int_mask = old_valid & ~data;
|
||||
if (int_mask) {
|
||||
pch_pic_update_irq(s, int_mask << 32, 1);
|
||||
}
|
||||
int_mask = ~old_valid & data;
|
||||
if (int_mask) {
|
||||
pch_pic_update_irq(s, int_mask << 32, 0);
|
||||
}
|
||||
break;
|
||||
case PCH_PIC_INT_EDGE_LO:
|
||||
s->intedge = get_writew_val(s->intedge, data, 0);
|
||||
break;
|
||||
case PCH_PIC_INT_EDGE_HI:
|
||||
s->intedge = get_writew_val(s->intedge, data, 1);
|
||||
break;
|
||||
case PCH_PIC_INT_CLEAR_LO:
|
||||
if (s->intedge & data) {
|
||||
s->intirr &= (~data);
|
||||
pch_pic_update_irq(s, data, 0);
|
||||
s->intisr &= (~data);
|
||||
}
|
||||
break;
|
||||
case PCH_PIC_INT_CLEAR_HI:
|
||||
value <<= 32;
|
||||
if (s->intedge & value) {
|
||||
s->intirr &= (~value);
|
||||
pch_pic_update_irq(s, value, 0);
|
||||
s->intisr &= (~value);
|
||||
}
|
||||
break;
|
||||
case PCH_PIC_HTMSI_EN_LO:
|
||||
s->htmsi_en = get_writew_val(s->htmsi_en, data, 0);
|
||||
break;
|
||||
case PCH_PIC_HTMSI_EN_HI:
|
||||
s->htmsi_en = get_writew_val(s->htmsi_en, data, 1);
|
||||
break;
|
||||
case PCH_PIC_AUTO_CTRL0_LO:
|
||||
case PCH_PIC_AUTO_CTRL0_HI:
|
||||
case PCH_PIC_AUTO_CTRL1_LO:
|
||||
case PCH_PIC_AUTO_CTRL1_HI:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t loongarch_pch_pic_high_readw(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
|
||||
uint64_t val = 0;
|
||||
uint32_t offset = addr & 0xfff;
|
||||
|
||||
switch (offset) {
|
||||
case STATUS_LO_START:
|
||||
val = (uint32_t)(s->intisr & (~s->int_mask));
|
||||
break;
|
||||
case STATUS_HI_START:
|
||||
val = (s->intisr & (~s->int_mask)) >> 32;
|
||||
break;
|
||||
case POL_LO_START:
|
||||
val = (uint32_t)s->int_polarity;
|
||||
break;
|
||||
case POL_HI_START:
|
||||
val = s->int_polarity >> 32;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
trace_loongarch_pch_pic_high_readw(size, addr, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
static void loongarch_pch_pic_high_writew(void *opaque, hwaddr addr,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
|
||||
uint32_t offset, data = (uint32_t)value;
|
||||
offset = addr & 0xfff;
|
||||
|
||||
trace_loongarch_pch_pic_high_writew(size, addr, data);
|
||||
|
||||
switch (offset) {
|
||||
case STATUS_LO_START:
|
||||
s->intisr = get_writew_val(s->intisr, data, 0);
|
||||
break;
|
||||
case STATUS_HI_START:
|
||||
s->intisr = get_writew_val(s->intisr, data, 1);
|
||||
break;
|
||||
case POL_LO_START:
|
||||
s->int_polarity = get_writew_val(s->int_polarity, data, 0);
|
||||
break;
|
||||
case POL_HI_START:
|
||||
s->int_polarity = get_writew_val(s->int_polarity, data, 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t loongarch_pch_pic_readb(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
|
||||
uint64_t val = 0;
|
||||
uint32_t offset = (addr & 0xfff) + PCH_PIC_ROUTE_ENTRY_OFFSET;
|
||||
int64_t offset_tmp;
|
||||
|
||||
switch (offset) {
|
||||
case PCH_PIC_HTMSI_VEC_OFFSET ... PCH_PIC_HTMSI_VEC_END:
|
||||
offset_tmp = offset - PCH_PIC_HTMSI_VEC_OFFSET;
|
||||
if (offset_tmp >= 0 && offset_tmp < 64) {
|
||||
val = s->htmsi_vector[offset_tmp];
|
||||
}
|
||||
break;
|
||||
case PCH_PIC_ROUTE_ENTRY_OFFSET ... PCH_PIC_ROUTE_ENTRY_END:
|
||||
offset_tmp = offset - PCH_PIC_ROUTE_ENTRY_OFFSET;
|
||||
if (offset_tmp >= 0 && offset_tmp < 64) {
|
||||
val = s->route_entry[offset_tmp];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
trace_loongarch_pch_pic_readb(size, addr, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
static void loongarch_pch_pic_writeb(void *opaque, hwaddr addr,
|
||||
uint64_t data, unsigned size)
|
||||
{
|
||||
LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
|
||||
int32_t offset_tmp;
|
||||
uint32_t offset = (addr & 0xfff) + PCH_PIC_ROUTE_ENTRY_OFFSET;
|
||||
|
||||
trace_loongarch_pch_pic_writeb(size, addr, data);
|
||||
|
||||
switch (offset) {
|
||||
case PCH_PIC_HTMSI_VEC_OFFSET ... PCH_PIC_HTMSI_VEC_END:
|
||||
offset_tmp = offset - PCH_PIC_HTMSI_VEC_OFFSET;
|
||||
if (offset_tmp >= 0 && offset_tmp < 64) {
|
||||
s->htmsi_vector[offset_tmp] = (uint8_t)(data & 0xff);
|
||||
}
|
||||
break;
|
||||
case PCH_PIC_ROUTE_ENTRY_OFFSET ... PCH_PIC_ROUTE_ENTRY_END:
|
||||
offset_tmp = offset - PCH_PIC_ROUTE_ENTRY_OFFSET;
|
||||
if (offset_tmp >= 0 && offset_tmp < 64) {
|
||||
s->route_entry[offset_tmp] = (uint8_t)(data & 0xff);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps loongarch_pch_pic_reg32_low_ops = {
|
||||
.read = loongarch_pch_pic_low_readw,
|
||||
.write = loongarch_pch_pic_low_writew,
|
||||
.valid = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 8,
|
||||
},
|
||||
.impl = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
static const MemoryRegionOps loongarch_pch_pic_reg32_high_ops = {
|
||||
.read = loongarch_pch_pic_high_readw,
|
||||
.write = loongarch_pch_pic_high_writew,
|
||||
.valid = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 8,
|
||||
},
|
||||
.impl = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
static const MemoryRegionOps loongarch_pch_pic_reg8_ops = {
|
||||
.read = loongarch_pch_pic_readb,
|
||||
.write = loongarch_pch_pic_writeb,
|
||||
.valid = {
|
||||
.min_access_size = 1,
|
||||
.max_access_size = 1,
|
||||
},
|
||||
.impl = {
|
||||
.min_access_size = 1,
|
||||
.max_access_size = 1,
|
||||
},
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
static void loongarch_pch_pic_reset(DeviceState *d)
|
||||
{
|
||||
LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(d);
|
||||
int i;
|
||||
|
||||
s->int_mask = -1;
|
||||
s->htmsi_en = 0x0;
|
||||
s->intedge = 0x0;
|
||||
s->intclr = 0x0;
|
||||
s->auto_crtl0 = 0x0;
|
||||
s->auto_crtl1 = 0x0;
|
||||
for (i = 0; i < 64; i++) {
|
||||
s->route_entry[i] = 0x1;
|
||||
s->htmsi_vector[i] = 0x0;
|
||||
}
|
||||
s->intirr = 0x0;
|
||||
s->intisr = 0x0;
|
||||
s->last_intirr = 0x0;
|
||||
s->int_polarity = 0x0;
|
||||
}
|
||||
|
||||
static void loongarch_pch_pic_init(Object *obj)
|
||||
{
|
||||
LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
|
||||
memory_region_init_io(&s->iomem32_low, obj,
|
||||
&loongarch_pch_pic_reg32_low_ops,
|
||||
s, PCH_PIC_NAME(.reg32_part1), 0x100);
|
||||
memory_region_init_io(&s->iomem8, obj, &loongarch_pch_pic_reg8_ops,
|
||||
s, PCH_PIC_NAME(.reg8), 0x2a0);
|
||||
memory_region_init_io(&s->iomem32_high, obj,
|
||||
&loongarch_pch_pic_reg32_high_ops,
|
||||
s, PCH_PIC_NAME(.reg32_part2), 0xc60);
|
||||
sysbus_init_mmio(sbd, &s->iomem32_low);
|
||||
sysbus_init_mmio(sbd, &s->iomem8);
|
||||
sysbus_init_mmio(sbd, &s->iomem32_high);
|
||||
|
||||
qdev_init_gpio_out(DEVICE(obj), s->parent_irq, PCH_PIC_IRQ_NUM);
|
||||
qdev_init_gpio_in(DEVICE(obj), pch_pic_irq_handler, PCH_PIC_IRQ_NUM);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_loongarch_pch_pic = {
|
||||
.name = TYPE_LOONGARCH_PCH_PIC,
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT64(int_mask, LoongArchPCHPIC),
|
||||
VMSTATE_UINT64(htmsi_en, LoongArchPCHPIC),
|
||||
VMSTATE_UINT64(intedge, LoongArchPCHPIC),
|
||||
VMSTATE_UINT64(intclr, LoongArchPCHPIC),
|
||||
VMSTATE_UINT64(auto_crtl0, LoongArchPCHPIC),
|
||||
VMSTATE_UINT64(auto_crtl1, LoongArchPCHPIC),
|
||||
VMSTATE_UINT8_ARRAY(route_entry, LoongArchPCHPIC, 64),
|
||||
VMSTATE_UINT8_ARRAY(htmsi_vector, LoongArchPCHPIC, 64),
|
||||
VMSTATE_UINT64(last_intirr, LoongArchPCHPIC),
|
||||
VMSTATE_UINT64(intirr, LoongArchPCHPIC),
|
||||
VMSTATE_UINT64(intisr, LoongArchPCHPIC),
|
||||
VMSTATE_UINT64(int_polarity, LoongArchPCHPIC),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void loongarch_pch_pic_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->reset = loongarch_pch_pic_reset;
|
||||
dc->vmsd = &vmstate_loongarch_pch_pic;
|
||||
}
|
||||
|
||||
static const TypeInfo loongarch_pch_pic_info = {
|
||||
.name = TYPE_LOONGARCH_PCH_PIC,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(LoongArchPCHPIC),
|
||||
.instance_init = loongarch_pch_pic_init,
|
||||
.class_init = loongarch_pch_pic_class_init,
|
||||
};
|
||||
|
||||
static void loongarch_pch_pic_register_types(void)
|
||||
{
|
||||
type_register_static(&loongarch_pch_pic_info);
|
||||
}
|
||||
|
||||
type_init(loongarch_pch_pic_register_types)
|
@ -64,3 +64,4 @@ specific_ss.add(when: 'CONFIG_GOLDFISH_PIC', if_true: files('goldfish_pic.c'))
|
||||
specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c'))
|
||||
specific_ss.add(when: 'CONFIG_NIOS2_VIC', if_true: files('nios2_vic.c'))
|
||||
specific_ss.add(when: 'CONFIG_LOONGARCH_IPI', if_true: files('loongarch_ipi.c'))
|
||||
specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC', if_true: files('loongarch_pch_pic.c'))
|
||||
|
@ -291,3 +291,12 @@ sh_intc_set(int id, int enable) "setting interrupt group %d to %d"
|
||||
# loongarch_ipi.c
|
||||
loongarch_ipi_read(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%"PRIx64
|
||||
loongarch_ipi_write(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%"PRIx64
|
||||
|
||||
# loongarch_pch_pic.c
|
||||
loongarch_pch_pic_irq_handler(int irq, int level) "irq %d level %d"
|
||||
loongarch_pch_pic_low_readw(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64
|
||||
loongarch_pch_pic_low_writew(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64
|
||||
loongarch_pch_pic_high_readw(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64
|
||||
loongarch_pch_pic_high_writew(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64
|
||||
loongarch_pch_pic_readb(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64
|
||||
loongarch_pch_pic_writeb(unsigned size, uint64_t addr, uint64_t val) "size: %u addr: 0x%"PRIx64 "val: 0x%" PRIx64
|
||||
|
@ -3,3 +3,4 @@ config LOONGARCH_VIRT
|
||||
select PCI
|
||||
select PCI_EXPRESS_GENERIC_BRIDGE
|
||||
select LOONGARCH_IPI
|
||||
select LOONGARCH_PCH_PIC
|
||||
|
69
include/hw/intc/loongarch_pch_pic.h
Normal file
69
include/hw/intc/loongarch_pch_pic.h
Normal file
@ -0,0 +1,69 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* LoongArch 7A1000 I/O interrupt controller definitions
|
||||
*
|
||||
* Copyright (c) 2021 Loongson Technology Corporation Limited
|
||||
*/
|
||||
|
||||
#define TYPE_LOONGARCH_PCH_PIC "loongarch_pch_pic"
|
||||
#define PCH_PIC_NAME(name) TYPE_LOONGARCH_PCH_PIC#name
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(LoongArchPCHPIC, LOONGARCH_PCH_PIC)
|
||||
|
||||
#define PCH_PIC_IRQ_START 0
|
||||
#define PCH_PIC_IRQ_END 63
|
||||
#define PCH_PIC_IRQ_NUM 64
|
||||
#define PCH_PIC_INT_ID_VAL 0x7000000UL
|
||||
#define PCH_PIC_INT_ID_NUM 0x3f0001UL
|
||||
|
||||
#define PCH_PIC_INT_ID_LO 0x00
|
||||
#define PCH_PIC_INT_ID_HI 0x04
|
||||
#define PCH_PIC_INT_MASK_LO 0x20
|
||||
#define PCH_PIC_INT_MASK_HI 0x24
|
||||
#define PCH_PIC_HTMSI_EN_LO 0x40
|
||||
#define PCH_PIC_HTMSI_EN_HI 0x44
|
||||
#define PCH_PIC_INT_EDGE_LO 0x60
|
||||
#define PCH_PIC_INT_EDGE_HI 0x64
|
||||
#define PCH_PIC_INT_CLEAR_LO 0x80
|
||||
#define PCH_PIC_INT_CLEAR_HI 0x84
|
||||
#define PCH_PIC_AUTO_CTRL0_LO 0xc0
|
||||
#define PCH_PIC_AUTO_CTRL0_HI 0xc4
|
||||
#define PCH_PIC_AUTO_CTRL1_LO 0xe0
|
||||
#define PCH_PIC_AUTO_CTRL1_HI 0xe4
|
||||
#define PCH_PIC_ROUTE_ENTRY_OFFSET 0x100
|
||||
#define PCH_PIC_ROUTE_ENTRY_END 0x13f
|
||||
#define PCH_PIC_HTMSI_VEC_OFFSET 0x200
|
||||
#define PCH_PIC_HTMSI_VEC_END 0x23f
|
||||
#define PCH_PIC_INT_STATUS_LO 0x3a0
|
||||
#define PCH_PIC_INT_STATUS_HI 0x3a4
|
||||
#define PCH_PIC_INT_POL_LO 0x3e0
|
||||
#define PCH_PIC_INT_POL_HI 0x3e4
|
||||
|
||||
#define STATUS_LO_START 0
|
||||
#define STATUS_HI_START 0x4
|
||||
#define POL_LO_START 0x40
|
||||
#define POL_HI_START 0x44
|
||||
struct LoongArchPCHPIC {
|
||||
SysBusDevice parent_obj;
|
||||
qemu_irq parent_irq[64];
|
||||
uint64_t int_mask; /*0x020 interrupt mask register*/
|
||||
uint64_t htmsi_en; /*0x040 1=msi*/
|
||||
uint64_t intedge; /*0x060 edge=1 level =0*/
|
||||
uint64_t intclr; /*0x080 for clean edge int,set 1 clean,set 0 is noused*/
|
||||
uint64_t auto_crtl0; /*0x0c0*/
|
||||
uint64_t auto_crtl1; /*0x0e0*/
|
||||
uint64_t last_intirr; /* edge detection */
|
||||
uint64_t intirr; /* 0x380 interrupt request register */
|
||||
uint64_t intisr; /* 0x3a0 interrupt service register */
|
||||
/*
|
||||
* 0x3e0 interrupt level polarity selection
|
||||
* register 0 for high level trigger
|
||||
*/
|
||||
uint64_t int_polarity;
|
||||
|
||||
uint8_t route_entry[64]; /*0x100 - 0x138*/
|
||||
uint8_t htmsi_vector[64]; /*0x200 - 0x238*/
|
||||
|
||||
MemoryRegion iomem32_low;
|
||||
MemoryRegion iomem32_high;
|
||||
MemoryRegion iomem8;
|
||||
};
|
30
include/hw/pci-host/ls7a.h
Normal file
30
include/hw/pci-host/ls7a.h
Normal file
@ -0,0 +1,30 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* QEMU LoongArch CPU
|
||||
*
|
||||
* Copyright (c) 2021 Loongson Technology Corporation Limited
|
||||
*/
|
||||
|
||||
#ifndef HW_LS7A_H
|
||||
#define HW_LS7A_H
|
||||
|
||||
#include "hw/pci/pci.h"
|
||||
#include "hw/pci/pcie_host.h"
|
||||
#include "hw/pci-host/pam.h"
|
||||
#include "qemu/units.h"
|
||||
#include "qemu/range.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#define LS7A_PCH_REG_BASE 0x10000000UL
|
||||
#define LS7A_IOAPIC_REG_BASE (LS7A_PCH_REG_BASE)
|
||||
#define LS7A_PCH_MSI_ADDR_LOW 0x2FF00000UL
|
||||
|
||||
/*
|
||||
* According to the kernel pch irq start from 64 offset
|
||||
* 0 ~ 16 irqs used for non-pci device while 16 ~ 64 irqs
|
||||
* used for pci device.
|
||||
*/
|
||||
#define PCH_PIC_IRQ_OFFSET 64
|
||||
#define LS7A_DEVICE_IRQS 16
|
||||
#define LS7A_PCI_IRQS 48
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user