qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH-for-5.2 4/4] hw/char/serial: Use the Clock API to feed the UART r


From: Philippe Mathieu-Daudé
Subject: [PATCH-for-5.2 4/4] hw/char/serial: Use the Clock API to feed the UART reference clock
Date: Thu, 6 Aug 2020 15:03:40 +0200

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(-)

diff --git a/include/hw/char/serial.h b/include/hw/char/serial.h
index 75c71adfd2..1c7a4df2ab 100644
--- a/include/hw/char/serial.h
+++ b/include/hw/char/serial.h
@@ -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;
diff --git a/hw/char/serial.c b/hw/char/serial.c
index 2ddc73f255..701c670fd5 100644
--- a/hw/char/serial.c
+++ b/hw/char/serial.c
@@ -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,
 };
 
-- 
2.21.3




reply via email to

[Prev in Thread] Current Thread [Next in Thread]