aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2011-05-26 17:34:11 +0100
committerAndrzej Zaborowski <andrew.zaborowski@intel.com>2011-06-15 13:23:37 +0200
commiteb47d7c5d96060040931c42773ee07e61e547af9 (patch)
treed9b5fd796bf72241d3c1271b90814ca152981cfc
parent953ffe0f935f40c0d6061d69e76e0339393b54f8 (diff)
hw/9118.c: Implement active-low interrupt support
The 9118 ethernet controller interrupt line is active low unless the IRQ config register is programmed to set both the IRQ_POL (polarity: active-high) and IRQ_TYPE (type: push-pull) bits: implement support for inverting the irq output in other configurations. This also requires that we support setting the bits in the first place, and that we correctly preserve them across software reset. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Andrzej Zaborowski <andrew.zaborowski@intel.com>
-rw-r--r--hw/lan9118.c12
1 files changed, 9 insertions, 3 deletions
diff --git a/hw/lan9118.c b/hw/lan9118.c
index 4c42fe94c2..3f3c05df4c 100644
--- a/hw/lan9118.c
+++ b/hw/lan9118.c
@@ -228,6 +228,12 @@ static void lan9118_update(lan9118_state *s)
if ((s->irq_cfg & IRQ_EN) == 0) {
level = 0;
}
+ if ((s->irq_cfg & (IRQ_TYPE | IRQ_POL)) != (IRQ_TYPE | IRQ_POL)) {
+ /* Interrupt is active low unless we're configured as
+ * active-high polarity, push-pull type.
+ */
+ level = !level;
+ }
qemu_set_irq(s->irq, level);
}
@@ -294,8 +300,7 @@ static void phy_reset(lan9118_state *s)
static void lan9118_reset(DeviceState *d)
{
lan9118_state *s = FROM_SYSBUS(lan9118_state, sysbus_from_qdev(d));
-
- s->irq_cfg &= ~(IRQ_TYPE | IRQ_POL);
+ s->irq_cfg &= (IRQ_TYPE | IRQ_POL);
s->int_sts = 0;
s->int_en = 0;
s->fifo_int = 0x48000000;
@@ -904,7 +909,8 @@ static void lan9118_writel(void *opaque, target_phys_addr_t offset,
switch (offset) {
case CSR_IRQ_CFG:
/* TODO: Implement interrupt deassertion intervals. */
- s->irq_cfg = (s->irq_cfg & IRQ_INT) | (val & IRQ_EN);
+ val &= (IRQ_EN | IRQ_POL | IRQ_TYPE);
+ s->irq_cfg = (s->irq_cfg & IRQ_INT) | val;
break;
case CSR_INT_STS:
s->int_sts &= ~val;