diff --git a/hw/char/ibex_uart.c b/hw/char/ibex_uart.c index 45cd724998..ab6247de89 100644 --- a/hw/char/ibex_uart.c +++ b/hw/char/ibex_uart.c @@ -28,6 +28,7 @@ #include "qemu/osdep.h" #include "hw/char/ibex_uart.h" #include "hw/irq.h" +#include "hw/qdev-clock.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" #include "qemu/log.h" @@ -203,6 +204,17 @@ static void ibex_uart_reset(DeviceState *dev) ibex_uart_update_irqs(s); } +static uint64_t ibex_uart_get_baud(IbexUartState *s) +{ + uint64_t baud; + + baud = ((s->uart_ctrl & UART_CTRL_NCO) >> 16); + baud *= clock_get_hz(s->f_clk); + baud >>= 20; + + return baud; +} + static uint64_t ibex_uart_read(void *opaque, hwaddr addr, unsigned int size) { @@ -329,9 +341,7 @@ static void ibex_uart_write(void *opaque, hwaddr addr, "%s: UART_CTRL_RXBLVL is not supported\n", __func__); } if (value & UART_CTRL_NCO) { - uint64_t baud = ((value & UART_CTRL_NCO) >> 16); - baud *= 1000; - baud >>= 20; + uint64_t baud = ibex_uart_get_baud(s); s->char_tx_time = (NANOSECONDS_PER_SECOND / baud) * 10; } @@ -385,6 +395,16 @@ static void ibex_uart_write(void *opaque, hwaddr addr, } } +static void ibex_uart_clk_update(void *opaque) +{ + IbexUartState *s = opaque; + + /* recompute uart's speed on clock change */ + uint64_t baud = ibex_uart_get_baud(s); + + s->char_tx_time = (NANOSECONDS_PER_SECOND / baud) * 10; +} + static void fifo_trigger_update(void *opaque) { IbexUartState *s = opaque; @@ -444,6 +464,10 @@ static void ibex_uart_init(Object *obj) { IbexUartState *s = IBEX_UART(obj); + s->f_clk = qdev_init_clock_in(DEVICE(obj), "f_clock", + ibex_uart_clk_update, s); + clock_set_hz(s->f_clk, IBEX_UART_CLOCK); + sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->tx_watermark); sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->rx_watermark); sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->tx_empty); diff --git a/include/hw/char/ibex_uart.h b/include/hw/char/ibex_uart.h index 2bec772615..6d81051161 100644 --- a/include/hw/char/ibex_uart.h +++ b/include/hw/char/ibex_uart.h @@ -72,6 +72,7 @@ #define IBEX_UART_TIMEOUT_CTRL 0x2c #define IBEX_UART_TX_FIFO_SIZE 16 +#define IBEX_UART_CLOCK 50000000 /* 50MHz clock */ #define TYPE_IBEX_UART "ibex-uart" #define IBEX_UART(obj) \ @@ -101,6 +102,8 @@ typedef struct { uint32_t uart_val; uint32_t uart_timeout_ctrl; + Clock *f_clk; + CharBackend chr; qemu_irq tx_watermark; qemu_irq rx_watermark;