aspeed: vic: Add support for legacy register interface

The legacy interface only supported up to 32 IRQs, which became
restrictive around the AST2400 generation. QEMU support for the SoCs
started with the AST2400 along with an effort to reimplement and
upstream drivers for Linux, so up until this point the consumers of the
QEMU ASPEED support only required the 64 IRQ register interface.

In an effort to support older BMC firmware, add support for the 32 IRQ
interface.

Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
Signed-off-by: Cédric Le Goater <clg@kaod.org>
Reviewed-by: Joel Stanley <joel@jms.id.au>
Message-id: 20190618165311.27066-22-clg@kaod.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Andrew Jeffery 2019-07-01 17:26:18 +01:00 committed by Peter Maydell
parent 118c82e7ff
commit ebd205c080

View File

@ -104,54 +104,63 @@ static void aspeed_vic_set_irq(void *opaque, int irq, int level)
static uint64_t aspeed_vic_read(void *opaque, hwaddr offset, unsigned size)
{
uint64_t val;
const bool high = !!(offset & 0x4);
hwaddr n_offset = (offset & ~0x4);
AspeedVICState *s = (AspeedVICState *)opaque;
hwaddr n_offset;
uint64_t val;
bool high;
if (offset < AVIC_NEW_BASE_OFFSET) {
qemu_log_mask(LOG_UNIMP, "%s: Ignoring read from legacy registers "
"at 0x%" HWADDR_PRIx "[%u]\n", __func__, offset, size);
return 0;
high = false;
n_offset = offset;
} else {
high = !!(offset & 0x4);
n_offset = (offset & ~0x4);
}
n_offset -= AVIC_NEW_BASE_OFFSET;
switch (n_offset) {
case 0x0: /* IRQ Status */
case 0x80: /* IRQ Status */
case 0x00:
val = s->raw & ~s->select & s->enable;
break;
case 0x08: /* FIQ Status */
case 0x88: /* FIQ Status */
case 0x04:
val = s->raw & s->select & s->enable;
break;
case 0x10: /* Raw Interrupt Status */
case 0x90: /* Raw Interrupt Status */
case 0x08:
val = s->raw;
break;
case 0x18: /* Interrupt Selection */
case 0x98: /* Interrupt Selection */
case 0x0c:
val = s->select;
break;
case 0x20: /* Interrupt Enable */
case 0xa0: /* Interrupt Enable */
case 0x10:
val = s->enable;
break;
case 0x30: /* Software Interrupt */
case 0xb0: /* Software Interrupt */
case 0x18:
val = s->trigger;
break;
case 0x40: /* Interrupt Sensitivity */
case 0xc0: /* Interrupt Sensitivity */
case 0x24:
val = s->sense;
break;
case 0x48: /* Interrupt Both Edge Trigger Control */
case 0xc8: /* Interrupt Both Edge Trigger Control */
case 0x28:
val = s->dual_edge;
break;
case 0x50: /* Interrupt Event */
case 0xd0: /* Interrupt Event */
case 0x2c:
val = s->event;
break;
case 0x60: /* Edge Triggered Interrupt Status */
case 0xe0: /* Edge Triggered Interrupt Status */
val = s->raw & ~s->sense;
break;
/* Illegal */
case 0x28: /* Interrupt Enable Clear */
case 0x38: /* Software Interrupt Clear */
case 0x58: /* Edge Triggered Interrupt Clear */
case 0xa8: /* Interrupt Enable Clear */
case 0xb8: /* Software Interrupt Clear */
case 0xd8: /* Edge Triggered Interrupt Clear */
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Read of write-only register with offset 0x%"
HWADDR_PRIx "\n", __func__, offset);
@ -166,6 +175,8 @@ static uint64_t aspeed_vic_read(void *opaque, hwaddr offset, unsigned size)
}
if (high) {
val = extract64(val, 32, 19);
} else {
val = extract64(val, 0, 32);
}
trace_aspeed_vic_read(offset, size, val);
return val;
@ -174,19 +185,18 @@ static uint64_t aspeed_vic_read(void *opaque, hwaddr offset, unsigned size)
static void aspeed_vic_write(void *opaque, hwaddr offset, uint64_t data,
unsigned size)
{
const bool high = !!(offset & 0x4);
hwaddr n_offset = (offset & ~0x4);
AspeedVICState *s = (AspeedVICState *)opaque;
hwaddr n_offset;
bool high;
if (offset < AVIC_NEW_BASE_OFFSET) {
qemu_log_mask(LOG_UNIMP,
"%s: Ignoring write to legacy registers at 0x%"
HWADDR_PRIx "[%u] <- 0x%" PRIx64 "\n", __func__, offset,
size, data);
return;
high = false;
n_offset = offset;
} else {
high = !!(offset & 0x4);
n_offset = (offset & ~0x4);
}
n_offset -= AVIC_NEW_BASE_OFFSET;
trace_aspeed_vic_write(offset, size, data);
/* Given we have members using separate enable/clear registers, deposit64()
@ -201,7 +211,8 @@ static void aspeed_vic_write(void *opaque, hwaddr offset, uint64_t data,
}
switch (n_offset) {
case 0x18: /* Interrupt Selection */
case 0x98: /* Interrupt Selection */
case 0x0c:
/* Register has deposit64() semantics - overwrite requested 32 bits */
if (high) {
s->select &= AVIC_L_MASK;
@ -210,21 +221,25 @@ static void aspeed_vic_write(void *opaque, hwaddr offset, uint64_t data,
}
s->select |= data;
break;
case 0x20: /* Interrupt Enable */
case 0xa0: /* Interrupt Enable */
case 0x10:
s->enable |= data;
break;
case 0x28: /* Interrupt Enable Clear */
case 0xa8: /* Interrupt Enable Clear */
case 0x14:
s->enable &= ~data;
break;
case 0x30: /* Software Interrupt */
case 0xb0: /* Software Interrupt */
case 0x18:
qemu_log_mask(LOG_UNIMP, "%s: Software interrupts unavailable. "
"IRQs requested: 0x%016" PRIx64 "\n", __func__, data);
break;
case 0x38: /* Software Interrupt Clear */
case 0xb8: /* Software Interrupt Clear */
case 0x1c:
qemu_log_mask(LOG_UNIMP, "%s: Software interrupts unavailable. "
"IRQs to be cleared: 0x%016" PRIx64 "\n", __func__, data);
break;
case 0x50: /* Interrupt Event */
case 0xd0: /* Interrupt Event */
/* Register has deposit64() semantics - overwrite the top four valid
* IRQ bits, as only the top four IRQs (GPIOs) can change their event
* type */
@ -236,15 +251,21 @@ static void aspeed_vic_write(void *opaque, hwaddr offset, uint64_t data,
"Ignoring invalid write to interrupt event register");
}
break;
case 0x58: /* Edge Triggered Interrupt Clear */
case 0xd8: /* Edge Triggered Interrupt Clear */
case 0x38:
s->raw &= ~(data & ~s->sense);
break;
case 0x00: /* IRQ Status */
case 0x08: /* FIQ Status */
case 0x10: /* Raw Interrupt Status */
case 0x40: /* Interrupt Sensitivity */
case 0x48: /* Interrupt Both Edge Trigger Control */
case 0x60: /* Edge Triggered Interrupt Status */
case 0x80: /* IRQ Status */
case 0x00:
case 0x88: /* FIQ Status */
case 0x04:
case 0x90: /* Raw Interrupt Status */
case 0x08:
case 0xc0: /* Interrupt Sensitivity */
case 0x24:
case 0xc8: /* Interrupt Both Edge Trigger Control */
case 0x28:
case 0xe0: /* Edge Triggered Interrupt Status */
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Write of read-only register with offset 0x%"
HWADDR_PRIx "\n", __func__, offset);