[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PULL 19/20] hw/char/exynos4210_uart: Add receive DMA support
From: |
Peter Maydell |
Subject: |
[PULL 19/20] hw/char/exynos4210_uart: Add receive DMA support |
Date: |
Thu, 23 Jan 2020 15:30:40 +0000 |
From: Guenter Roeck <address@hidden>
To support receive DMA, we need to inform the DMA controller if receive data
is available. Otherwise the DMA controller keeps requesting data, causing
receive errors.
Implement this using an interrupt line. The instantiating code then needs
to connect the interrupt with the matching DMA controller GPIO pin.
Reviewed-by: Peter Maydell <address@hidden>
Signed-off-by: Guenter Roeck <address@hidden>
Message-id: address@hidden
Signed-off-by: Peter Maydell <address@hidden>
---
hw/char/exynos4210_uart.c | 24 ++++++++++++++++++++++++
hw/char/trace-events | 2 ++
2 files changed, 26 insertions(+)
diff --git a/hw/char/exynos4210_uart.c b/hw/char/exynos4210_uart.c
index 363393cc753..20d85091072 100644
--- a/hw/char/exynos4210_uart.c
+++ b/hw/char/exynos4210_uart.c
@@ -154,6 +154,7 @@ typedef struct Exynos4210UartState {
CharBackend chr;
qemu_irq irq;
+ qemu_irq dmairq;
uint32_t channel;
@@ -261,6 +262,24 @@ exynos4210_uart_Rx_FIFO_trigger_level(const
Exynos4210UartState *s)
return exynos4210_uart_FIFO_trigger_level(s->channel, reg);
}
+/*
+ * Update Rx DMA busy signal if Rx DMA is enabled. For simplicity,
+ * mark DMA as busy if DMA is enabled and the receive buffer is empty.
+ */
+static void exynos4210_uart_update_dmabusy(Exynos4210UartState *s)
+{
+ bool rx_dma_enabled = (s->reg[I_(UCON)] & 0x03) == 0x02;
+ uint32_t count = fifo_elements_number(&s->rx);
+
+ if (rx_dma_enabled && !count) {
+ qemu_irq_raise(s->dmairq);
+ trace_exynos_uart_dmabusy(s->channel);
+ } else {
+ qemu_irq_lower(s->dmairq);
+ trace_exynos_uart_dmaready(s->channel);
+ }
+}
+
static void exynos4210_uart_update_irq(Exynos4210UartState *s)
{
/*
@@ -282,10 +301,12 @@ static void
exynos4210_uart_update_irq(Exynos4210UartState *s)
count = fifo_elements_number(&s->rx);
if ((count && !(s->reg[I_(UCON)] & 0x80)) ||
count >= exynos4210_uart_Rx_FIFO_trigger_level(s)) {
+ exynos4210_uart_update_dmabusy(s);
s->reg[I_(UINTSP)] |= UINTSP_RXD;
timer_del(s->fifo_timeout_timer);
}
} else if (s->reg[I_(UTRSTAT)] & UTRSTAT_Rx_BUFFER_DATA_READY) {
+ exynos4210_uart_update_dmabusy(s);
s->reg[I_(UINTSP)] |= UINTSP_RXD;
}
@@ -311,6 +332,7 @@ static void exynos4210_uart_timeout_int(void *opaque)
(s->reg[I_(UCON)] & (1 << 11))) {
s->reg[I_(UINTSP)] |= UINTSP_RXD;
s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_TIMEOUT;
+ exynos4210_uart_update_dmabusy(s);
exynos4210_uart_update_irq(s);
}
}
@@ -495,6 +517,7 @@ static uint64_t exynos4210_uart_read(void *opaque, hwaddr
offset,
s->reg[I_(UTRSTAT)] &= ~UTRSTAT_Rx_BUFFER_DATA_READY;
res = s->reg[I_(URXH)];
}
+ exynos4210_uart_update_dmabusy(s);
trace_exynos_uart_read(s->channel, offset,
exynos4210_uart_regname(offset), res);
return res;
@@ -661,6 +684,7 @@ static void exynos4210_uart_init(Object *obj)
sysbus_init_mmio(dev, &s->iomem);
sysbus_init_irq(dev, &s->irq);
+ sysbus_init_irq(dev, &s->dmairq);
}
static void exynos4210_uart_realize(DeviceState *dev, Error **errp)
diff --git a/hw/char/trace-events b/hw/char/trace-events
index cb73fee6a9d..6f938301d98 100644
--- a/hw/char/trace-events
+++ b/hw/char/trace-events
@@ -79,6 +79,8 @@ nrf51_uart_read(uint64_t addr, uint64_t r, unsigned int size)
"addr 0x%" PRIx64
nrf51_uart_write(uint64_t addr, uint64_t value, unsigned int size) "addr 0x%"
PRIx64 " value 0x%" PRIx64 " size %u"
# exynos4210_uart.c
+exynos_uart_dmabusy(uint32_t channel) "UART%d: DMA busy (Rx buffer empty)"
+exynos_uart_dmaready(uint32_t channel) "UART%d: DMA ready"
exynos_uart_irq_raised(uint32_t channel, uint32_t reg) "UART%d: IRQ raised:
0x%08"PRIx32
exynos_uart_irq_lowered(uint32_t channel) "UART%d: IRQ lowered"
exynos_uart_update_params(uint32_t channel, int speed, uint8_t parity, int
data, int stop, uint64_t wordtime) "UART%d: speed: %d, parity: %c, data bits:
%d, stop bits: %d wordtime: %"PRId64"ns"
--
2.20.1
- [PULL 06/20] hw/acpi: Remove extra indent in ACPI GED hotplug cb, (continued)
- [PULL 06/20] hw/acpi: Remove extra indent in ACPI GED hotplug cb, Peter Maydell, 2020/01/23
- [PULL 02/20] target/arm: Fix PAuth sbox functions, Peter Maydell, 2020/01/23
- [PULL 09/20] docs: Create stub system manual, Peter Maydell, 2020/01/23
- [PULL 08/20] qemu-nbd: Convert invocation documentation to rST, Peter Maydell, 2020/01/23
- [PULL 12/20] hw/misc/stm32f4xx_syscfg: Fix copy/paste error, Peter Maydell, 2020/01/23
- [PULL 14/20] hw/core/or-irq: Increase limit of or-lines to 48, Peter Maydell, 2020/01/23
- [PULL 13/20] dma/pl330: Convert to support tracing, Peter Maydell, 2020/01/23
- [PULL 15/20] hw/arm/exynos4210: Fix DMA initialization, Peter Maydell, 2020/01/23
- [PULL 11/20] target/arm/arch_dump: Add SVE notes, Peter Maydell, 2020/01/23
- [PULL 17/20] hw/char/exynos4210_uart: Implement post_load function, Peter Maydell, 2020/01/23
- [PULL 19/20] hw/char/exynos4210_uart: Add receive DMA support,
Peter Maydell <=
- [PULL 20/20] hw/arm/exynos4210: Connect serial port DMA busy signals with pl330, Peter Maydell, 2020/01/23
- [PULL 16/20] hw/char/exynos4210_uart: Convert to support tracing, Peter Maydell, 2020/01/23
- [PULL 18/20] hw/char/exynos4210_uart: Implement Rx FIFO level triggers and timeouts, Peter Maydell, 2020/01/23
- [PULL 10/20] qemu-block-drivers: Convert to rST, Peter Maydell, 2020/01/23