diff options
Diffstat (limited to 'hw/riscv/sifive_uart.c')
-rw-r--r-- | hw/riscv/sifive_uart.c | 194 |
1 files changed, 0 insertions, 194 deletions
diff --git a/hw/riscv/sifive_uart.c b/hw/riscv/sifive_uart.c deleted file mode 100644 index 9350482662..0000000000 --- a/hw/riscv/sifive_uart.c +++ /dev/null @@ -1,194 +0,0 @@ -/* - * QEMU model of the UART on the SiFive E300 and U500 series SOCs. - * - * Copyright (c) 2016 Stefan O'Rear - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2 or later, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "qemu/log.h" -#include "hw/sysbus.h" -#include "chardev/char.h" -#include "chardev/char-fe.h" -#include "hw/hw.h" -#include "hw/irq.h" -#include "hw/riscv/sifive_uart.h" - -/* - * Not yet implemented: - * - * Transmit FIFO using "qemu/fifo8.h" - */ - -/* Returns the state of the IP (interrupt pending) register */ -static uint64_t uart_ip(SiFiveUARTState *s) -{ - uint64_t ret = 0; - - uint64_t txcnt = SIFIVE_UART_GET_TXCNT(s->txctrl); - uint64_t rxcnt = SIFIVE_UART_GET_RXCNT(s->rxctrl); - - if (txcnt != 0) { - ret |= SIFIVE_UART_IP_TXWM; - } - if (s->rx_fifo_len > rxcnt) { - ret |= SIFIVE_UART_IP_RXWM; - } - - return ret; -} - -static void update_irq(SiFiveUARTState *s) -{ - int cond = 0; - if ((s->ie & SIFIVE_UART_IE_TXWM) || - ((s->ie & SIFIVE_UART_IE_RXWM) && s->rx_fifo_len)) { - cond = 1; - } - if (cond) { - qemu_irq_raise(s->irq); - } else { - qemu_irq_lower(s->irq); - } -} - -static uint64_t -uart_read(void *opaque, hwaddr addr, unsigned int size) -{ - SiFiveUARTState *s = opaque; - unsigned char r; - switch (addr) { - case SIFIVE_UART_RXFIFO: - if (s->rx_fifo_len) { - r = s->rx_fifo[0]; - memmove(s->rx_fifo, s->rx_fifo + 1, s->rx_fifo_len - 1); - s->rx_fifo_len--; - qemu_chr_fe_accept_input(&s->chr); - update_irq(s); - return r; - } - return 0x80000000; - - case SIFIVE_UART_TXFIFO: - return 0; /* Should check tx fifo */ - case SIFIVE_UART_IE: - return s->ie; - case SIFIVE_UART_IP: - return uart_ip(s); - case SIFIVE_UART_TXCTRL: - return s->txctrl; - case SIFIVE_UART_RXCTRL: - return s->rxctrl; - case SIFIVE_UART_DIV: - return s->div; - } - - qemu_log_mask(LOG_GUEST_ERROR, "%s: bad read: addr=0x%x\n", - __func__, (int)addr); - return 0; -} - -static void -uart_write(void *opaque, hwaddr addr, - uint64_t val64, unsigned int size) -{ - SiFiveUARTState *s = opaque; - uint32_t value = val64; - unsigned char ch = value; - - switch (addr) { - case SIFIVE_UART_TXFIFO: - qemu_chr_fe_write(&s->chr, &ch, 1); - update_irq(s); - return; - case SIFIVE_UART_IE: - s->ie = val64; - update_irq(s); - return; - case SIFIVE_UART_TXCTRL: - s->txctrl = val64; - return; - case SIFIVE_UART_RXCTRL: - s->rxctrl = val64; - return; - case SIFIVE_UART_DIV: - s->div = val64; - return; - } - qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%x v=0x%x\n", - __func__, (int)addr, (int)value); -} - -static const MemoryRegionOps uart_ops = { - .read = uart_read, - .write = uart_write, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 4 - } -}; - -static void uart_rx(void *opaque, const uint8_t *buf, int size) -{ - SiFiveUARTState *s = opaque; - - /* Got a byte. */ - if (s->rx_fifo_len >= sizeof(s->rx_fifo)) { - printf("WARNING: UART dropped char.\n"); - return; - } - s->rx_fifo[s->rx_fifo_len++] = *buf; - - update_irq(s); -} - -static int uart_can_rx(void *opaque) -{ - SiFiveUARTState *s = opaque; - - return s->rx_fifo_len < sizeof(s->rx_fifo); -} - -static void uart_event(void *opaque, QEMUChrEvent event) -{ -} - -static int uart_be_change(void *opaque) -{ - SiFiveUARTState *s = opaque; - - qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx, uart_event, - uart_be_change, s, NULL, true); - - return 0; -} - -/* - * Create UART device. - */ -SiFiveUARTState *sifive_uart_create(MemoryRegion *address_space, hwaddr base, - Chardev *chr, qemu_irq irq) -{ - SiFiveUARTState *s = g_malloc0(sizeof(SiFiveUARTState)); - s->irq = irq; - qemu_chr_fe_init(&s->chr, chr, &error_abort); - qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx, uart_event, - uart_be_change, s, NULL, true); - memory_region_init_io(&s->mmio, NULL, &uart_ops, s, - TYPE_SIFIVE_UART, SIFIVE_UART_MAX); - memory_region_add_subregion(address_space, base, &s->mmio); - return s; -} |