@@ -31,8 +31,10 @@
#include "qemu/fifo8.h"
#include "chardev/char.h"
#include "hw/sysbus.h"
+#include "hw/clock.h"
#define UART_FIFO_LENGTH 16 /* 16550A Fifo Length */
+#define UART_CLOCK_DIVISOR 16 /* baudrate is input clock / 16 */
typedef struct SerialState {
DeviceState parent;
@@ -57,6 +59,7 @@ typedef struct SerialState {
qemu_irq irq;
CharBackend chr;
int last_break_enable;
+ Clock *rclk; /* ReceiverClock */
uint32_t baudbase;
uint32_t tsr_retry;
guint watch_tag;
@@ -35,6 +35,7 @@
#include "qemu/error-report.h"
#include "trace.h"
#include "hw/qdev-properties.h"
+#include "hw/qdev-clock.h"
#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */
@@ -921,10 +922,36 @@ static int serial_be_change(void *opaque)
return 0;
}
+/* Change the main reference oscillator frequency. */
+void serial_set_frequency(SerialState *s, uint32_t frequency)
+{
+ s->baudbase = frequency;
+ serial_update_parameters(s);
+}
+
+static void serial_rclk_update(void *opaque)
+{
+ SerialState *s = opaque;
+
+ serial_set_frequency(s, clock_get_hz(s->rclk) / UART_CLOCK_DIVISOR);
+}
+
+static void serial_init(Object *obj)
+{
+ SerialState *s = SERIAL(obj);
+
+ s->rclk = qdev_init_clock_in(DEVICE(obj), "rclk", serial_rclk_update, s);
+}
+
static void serial_realize(DeviceState *dev, Error **errp)
{
SerialState *s = SERIAL(dev);
+ /* initialize the frequency in case the clock remains unconnected */
+ if (!clock_get(s->rclk)) {
+ clock_set_hz(s->rclk, s->baudbase);
+ }
+
s->modem_status_poll = timer_new_ns(QEMU_CLOCK_VIRTUAL, (QEMUTimerCB *) serial_update_msl, s);
s->fifo_timeout_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, (QEMUTimerCB *) fifo_timeout_int, s);
@@ -955,13 +982,6 @@ static void serial_unrealize(DeviceState *dev)
qemu_unregister_reset(serial_reset, s);
}
-/* Change the main reference oscillator frequency. */
-void serial_set_frequency(SerialState *s, uint32_t frequency)
-{
- s->baudbase = frequency;
- serial_update_parameters(s);
-}
-
const MemoryRegionOps serial_io_ops = {
.read = serial_ioport_read,
.write = serial_ioport_write,
@@ -994,6 +1014,7 @@ static const TypeInfo serial_info = {
.name = TYPE_SERIAL,
.parent = TYPE_DEVICE,
.instance_size = sizeof(SerialState),
+ .instance_init = serial_init,
.class_init = serial_class_init,
};
In the same chipset, UARTs can be clocked at different rate, or the input clock can be changed at runtime. The Clock API allow us to propagate such clock rate change to the device. Let the SerialState have its reference input clock (called 'rclk') and if not clock is connected to the device, use the currently provided frequency, to not modify the current code behavior. Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org> --- include/hw/char/serial.h | 3 +++ hw/char/serial.c | 35 ++++++++++++++++++++++++++++------- 2 files changed, 31 insertions(+), 7 deletions(-)