static void uart_write_rx_fifo(void *opaque, const uint8_t *buf, int size) { UartState *s = (UartState *)opaque; uint64_t new_rx_time = qemu_get_clock_ns(vm_clock); int i; if ((s->r[R_CR] & UART_CR_RX_DIS) || !(s->r[R_CR] & UART_CR_RX_EN)) { return; } s->r[R_SR] &= ~UART_SR_INTR_REMPTY; if (s->rx_count == RX_FIFO_SIZE) { s->r[R_CISR] |= UART_INTR_ROVR; } else { for (i = 0; i < size; i++) { s->r_fifo[s->rx_wpos] = buf[i]; s->rx_wpos = (s->rx_wpos + 1) % RX_FIFO_SIZE; s->rx_count++; if (s->rx_count == RX_FIFO_SIZE) { s->r[R_SR] |= UART_SR_INTR_RFUL; break; } if (s->rx_count >= s->r[R_RTRIG]) { s->r[R_SR] |= UART_SR_INTR_RTRIG; } } qemu_mod_timer(s->fifo_trigger_handle, new_rx_time + (s->char_tx_time * 4)); } uart_update_status(s); }
static uint64_t uart_read(void *opaque, hwaddr addr, unsigned int size) { struct xlx_uartlite *s = opaque; uint32_t r = 0; addr >>= 2; switch (addr) { case R_RX: r = s->rx_fifo[(s->rx_fifo_pos - s->rx_fifo_len) & 7]; if (s->rx_fifo_len) s->rx_fifo_len--; uart_update_status(s); uart_update_irq(s); qemu_chr_accept_input(s->chr); break; default: if (addr < ARRAY_SIZE(s->regs)) r = s->regs[addr]; DUART(qemu_log("%s addr=%x v=%x\n", __func__, addr, r)); break; } return r; }
static void uart_read_rx_fifo(UartState *s, uint32_t *c) { if ((s->r[R_CR] & UART_CR_RX_DIS) || !(s->r[R_CR] & UART_CR_RX_EN)) { return; } s->r[R_SR] &= ~UART_SR_INTR_RFUL; if (s->rx_count) { uint32_t rx_rpos = (RX_FIFO_SIZE + s->rx_wpos - s->rx_count) % RX_FIFO_SIZE; *c = s->r_fifo[rx_rpos]; s->rx_count--; if (!s->rx_count) { s->r[R_SR] |= UART_SR_INTR_REMPTY; } qemu_chr_accept_input(s->chr); } else { *c = 0; s->r[R_SR] |= UART_SR_INTR_REMPTY; } if (s->rx_count < s->r[R_RTRIG]) { s->r[R_SR] &= ~UART_SR_INTR_RTRIG; } uart_update_status(s); }
static gboolean cadence_uart_xmit(GIOChannel *chan, GIOCondition cond, void *opaque) { UartState *s = opaque; int ret; /* instant drain the fifo when there's no back-end */ if (!s->chr) { s->tx_count = 0; } if (!s->tx_count) { return FALSE; } ret = qemu_chr_fe_write(s->chr, s->tx_fifo, s->tx_count); s->tx_count -= ret; memmove(s->tx_fifo, s->tx_fifo + ret, s->tx_count); if (s->tx_count) { int r = qemu_chr_fe_add_watch(s->chr, G_IO_OUT, cadence_uart_xmit, s); assert(r); } uart_update_status(s); return FALSE; }
static void fifo_trigger_update(void *opaque) { UartState *s = (UartState *)opaque; s->r[R_CISR] |= UART_INTR_TIMEOUT; uart_update_status(s); }
static void fifo_trigger_update(void *opaque) { CadenceUARTState *s = opaque; s->r[R_CISR] |= UART_INTR_TIMEOUT; uart_update_status(s); }
static int cadence_uart_post_load(void *opaque, int version_id) { UartState *s = opaque; uart_parameters_setup(s); uart_update_status(s); return 0; }
static void uart_tx_redo(UartState *s) { uint64_t new_tx_time = qemu_get_clock_ns(vm_clock); qemu_mod_timer(s->tx_time_handle, new_tx_time + s->char_tx_time); s->r[R_SR] |= UART_SR_INTR_TEMPTY; uart_update_status(s); }
static void uart_event(void *opaque, int event) { UartState *s = (UartState *)opaque; uint8_t buf = '\0'; if (event == CHR_EVENT_BREAK) { uart_write_rx_fifo(opaque, &buf, 1); } uart_update_status(s); }
static int xilinx_uartlite_init(SysBusDevice *dev) { struct xlx_uartlite *s = FROM_SYSBUS(typeof (*s), dev); sysbus_init_irq(dev, &s->irq); uart_update_status(s); memory_region_init_io(&s->mmio, &uart_ops, s, "xilinx-uartlite", R_MAX * 4); sysbus_init_mmio(dev, &s->mmio); s->chr = qdev_init_chardev(&dev->qdev); if (s->chr) qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s); return 0; }
static void cadence_uart_reset(DeviceState *dev) { UartState *s = CADENCE_UART(dev); s->r[R_CR] = 0x00000128; s->r[R_IMR] = 0; s->r[R_CISR] = 0; s->r[R_RTRIG] = 0x00000020; s->r[R_BRGR] = 0x0000000F; s->r[R_TTRIG] = 0x00000020; uart_rx_reset(s); uart_tx_reset(s); uart_update_status(s); }
static int xilinx_uartlite_init(SysBusDevice *dev) { XilinxUARTLite *s = XILINX_UARTLITE(dev); sysbus_init_irq(dev, &s->irq); uart_update_status(s); memory_region_init_io(&s->mmio, OBJECT(s), &uart_ops, s, TYPE_XILINX_UARTLITE, R_MAX * 4); sysbus_init_mmio(dev, &s->mmio); s->chr = qemu_char_get_next_serial(); if (s->chr) qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s); return 0; }
static int xilinx_uartlite_init(SysBusDevice *dev) { struct xlx_uartlite *s = FROM_SYSBUS(typeof (*s), dev); int uart_regs; sysbus_init_irq(dev, &s->irq); uart_update_status(s); uart_regs = cpu_register_io_memory(uart_read, uart_write, s, DEVICE_NATIVE_ENDIAN); sysbus_init_mmio(dev, R_MAX * 4, uart_regs); s->chr = qdev_init_chardev(&dev->qdev); if (s->chr) qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s); return 0; }
static void uart_rx(void *opaque, const uint8_t *buf, int size) { struct xlx_uartlite *s = opaque; /* Got a byte. */ if (s->rx_fifo_len >= 8) { printf("WARNING: UART dropped char.\n"); return; } s->rx_fifo[s->rx_fifo_pos] = *buf; s->rx_fifo_pos++; s->rx_fifo_pos &= 0x7; s->rx_fifo_len++; uart_update_status(s); uart_update_irq(s); }
static void uart_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { CadenceUARTState *s = opaque; DB_PRINT(" offset:%x data:%08x\n", (unsigned)offset, (unsigned)value); offset >>= 2; if (offset >= CADENCE_UART_R_MAX) { return; } switch (offset) { case R_IER: /* ier (wts imr) */ s->r[R_IMR] |= value; break; case R_IDR: /* idr (wtc imr) */ s->r[R_IMR] &= ~value; break; case R_IMR: /* imr (read only) */ break; case R_CISR: /* cisr (wtc) */ s->r[R_CISR] &= ~value; break; case R_TX_RX: /* UARTDR */ switch (s->r[R_MR] & UART_MR_CHMODE) { case NORMAL_MODE: uart_write_tx_fifo(s, (uint8_t *) &value, 1); break; case LOCAL_LOOPBACK: uart_write_rx_fifo(opaque, (uint8_t *) &value, 1); break; } break; default: s->r[offset] = value; } switch (offset) { case R_CR: uart_ctrl_update(s); break; case R_MR: uart_parameters_setup(s); break; } uart_update_status(s); }
static void uart_read_rx_fifo(UartState *s, uint32_t *c) { if ((s->r[R_CR] & UART_CR_RX_DIS) || !(s->r[R_CR] & UART_CR_RX_EN)) { return; } if (s->rx_count) { uint32_t rx_rpos = (RX_FIFO_SIZE + s->rx_wpos - s->rx_count) % RX_FIFO_SIZE; *c = s->rx_fifo[rx_rpos]; s->rx_count--; qemu_chr_accept_input(s->chr); } else { *c = 0; } uart_update_status(s); }
static void uart_write(void *opaque, hwaddr addr, uint64_t val64, unsigned int size) { struct xlx_uartlite *s = opaque; uint32_t value = val64; unsigned char ch = value; addr >>= 2; switch (addr) { case R_STATUS: hw_error("write to UART STATUS?\n"); break; case R_CTRL: if (value & CONTROL_RST_RX) { s->rx_fifo_pos = 0; s->rx_fifo_len = 0; } s->regs[addr] = value; break; case R_TX: if (s->chr) qemu_chr_fe_write(s->chr, &ch, 1); s->regs[addr] = value; /* hax. */ s->regs[R_STATUS] |= STATUS_IE; break; default: DUART(printf("%s addr=%x v=%x\n", __func__, addr, value)); if (addr < ARRAY_SIZE(s->regs)) s->regs[addr] = value; break; } uart_update_status(s); uart_update_irq(s); }
static void uart_write_rx_fifo(void *opaque, const uint8_t *buf, int size) { UartState *s = (UartState *)opaque; uint64_t new_rx_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); int i; if ((s->r[R_CR] & UART_CR_RX_DIS) || !(s->r[R_CR] & UART_CR_RX_EN)) { return; } if (s->rx_count == RX_FIFO_SIZE) { s->r[R_CISR] |= UART_INTR_ROVR; } else { for (i = 0; i < size; i++) { s->rx_fifo[s->rx_wpos] = buf[i]; s->rx_wpos = (s->rx_wpos + 1) % RX_FIFO_SIZE; s->rx_count++; } timer_mod(s->fifo_trigger_handle, new_rx_time + (s->char_tx_time * 4)); } uart_update_status(s); }
static uint32_t uart_readl (void *opaque, target_phys_addr_t addr) { struct xlx_uartlite *s = opaque; uint32_t r = 0; addr >>= 2; switch (addr) { case R_RX: r = s->rx_fifo[(s->rx_fifo_pos - s->rx_fifo_len) & 7]; if (s->rx_fifo_len) s->rx_fifo_len--; uart_update_status(s); uart_update_irq(s); break; default: if (addr < ARRAY_SIZE(s->regs)) r = s->regs[addr]; DUART(qemu_log("%s addr=%x v=%x\n", __func__, addr, r)); break; } return r; }