qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Peter Maydell <peter.maydell@linaro.org>
To: qemu-devel@nongnu.org
Subject: [PULL 15/31] hw/char/cadence_uart: add clock support
Date: Thu, 30 Apr 2020 12:51:26 +0100	[thread overview]
Message-ID: <20200430115142.13430-16-peter.maydell@linaro.org> (raw)
In-Reply-To: <20200430115142.13430-1-peter.maydell@linaro.org>

From: Damien Hedde <damien.hedde@greensocs.com>

Switch the cadence uart to multi-phase reset and add the
reference clock input.

The input clock frequency is added to the migration structure.

The reference clock controls the baudrate generation. If it disabled,
any input characters and events are ignored.

If this clock remains unconnected, the uart behaves as before
(it default to a 50MHz ref clock).

Signed-off-by: Damien Hedde <damien.hedde@greensocs.com>
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-id: 20200406135251.157596-8-damien.hedde@greensocs.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 include/hw/char/cadence_uart.h |  1 +
 hw/char/cadence_uart.c         | 73 +++++++++++++++++++++++++++++-----
 hw/char/trace-events           |  3 ++
 3 files changed, 67 insertions(+), 10 deletions(-)

diff --git a/include/hw/char/cadence_uart.h b/include/hw/char/cadence_uart.h
index 47cec956c4b..2a179a572fc 100644
--- a/include/hw/char/cadence_uart.h
+++ b/include/hw/char/cadence_uart.h
@@ -49,6 +49,7 @@ typedef struct {
     CharBackend chr;
     qemu_irq irq;
     QEMUTimer *fifo_trigger_handle;
+    Clock *refclk;
 } CadenceUARTState;
 
 static inline DeviceState *cadence_uart_create(hwaddr addr,
diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c
index 22e47972f15..e196906c923 100644
--- a/hw/char/cadence_uart.c
+++ b/hw/char/cadence_uart.c
@@ -31,6 +31,8 @@
 #include "qemu/module.h"
 #include "hw/char/cadence_uart.h"
 #include "hw/irq.h"
+#include "hw/qdev-clock.h"
+#include "trace.h"
 
 #ifdef CADENCE_UART_ERR_DEBUG
 #define DB_PRINT(...) do { \
@@ -97,7 +99,7 @@
 #define LOCAL_LOOPBACK         (0x2 << UART_MR_CHMODE_SH)
 #define REMOTE_LOOPBACK        (0x3 << UART_MR_CHMODE_SH)
 
-#define UART_INPUT_CLK         50000000
+#define UART_DEFAULT_REF_CLK (50 * 1000 * 1000)
 
 #define R_CR       (0x00/4)
 #define R_MR       (0x04/4)
@@ -171,12 +173,15 @@ static void uart_send_breaks(CadenceUARTState *s)
 static void uart_parameters_setup(CadenceUARTState *s)
 {
     QEMUSerialSetParams ssp;
-    unsigned int baud_rate, packet_size;
+    unsigned int baud_rate, packet_size, input_clk;
+    input_clk = clock_get_hz(s->refclk);
 
-    baud_rate = (s->r[R_MR] & UART_MR_CLKS) ?
-            UART_INPUT_CLK / 8 : UART_INPUT_CLK;
+    baud_rate = (s->r[R_MR] & UART_MR_CLKS) ? input_clk / 8 : input_clk;
+    baud_rate /= (s->r[R_BRGR] * (s->r[R_BDIV] + 1));
+    trace_cadence_uart_baudrate(baud_rate);
+
+    ssp.speed = baud_rate;
 
-    ssp.speed = baud_rate / (s->r[R_BRGR] * (s->r[R_BDIV] + 1));
     packet_size = 1;
 
     switch (s->r[R_MR] & UART_MR_PAR) {
@@ -215,6 +220,13 @@ static void uart_parameters_setup(CadenceUARTState *s)
     }
 
     packet_size += ssp.data_bits + ssp.stop_bits;
+    if (ssp.speed == 0) {
+        /*
+         * Avoid division-by-zero below.
+         * TODO: find something better
+         */
+        ssp.speed = 1;
+    }
     s->char_tx_time = (NANOSECONDS_PER_SECOND / ssp.speed) * packet_size;
     qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
 }
@@ -340,6 +352,11 @@ static void uart_receive(void *opaque, const uint8_t *buf, int size)
     CadenceUARTState *s = opaque;
     uint32_t ch_mode = s->r[R_MR] & UART_MR_CHMODE;
 
+    /* ignore characters when unclocked or in reset */
+    if (!clock_is_enabled(s->refclk) || device_is_in_reset(DEVICE(s))) {
+        return;
+    }
+
     if (ch_mode == NORMAL_MODE || ch_mode == ECHO_MODE) {
         uart_write_rx_fifo(opaque, buf, size);
     }
@@ -353,6 +370,11 @@ static void uart_event(void *opaque, QEMUChrEvent event)
     CadenceUARTState *s = opaque;
     uint8_t buf = '\0';
 
+    /* ignore characters when unclocked or in reset */
+    if (!clock_is_enabled(s->refclk) || device_is_in_reset(DEVICE(s))) {
+        return;
+    }
+
     if (event == CHR_EVENT_BREAK) {
         uart_write_rx_fifo(opaque, &buf, 1);
     }
@@ -462,9 +484,9 @@ static const MemoryRegionOps uart_ops = {
     .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static void cadence_uart_reset(DeviceState *dev)
+static void cadence_uart_reset_init(Object *obj, ResetType type)
 {
-    CadenceUARTState *s = CADENCE_UART(dev);
+    CadenceUARTState *s = CADENCE_UART(obj);
 
     s->r[R_CR] = 0x00000128;
     s->r[R_IMR] = 0;
@@ -473,6 +495,11 @@ static void cadence_uart_reset(DeviceState *dev)
     s->r[R_BRGR] = 0x0000028B;
     s->r[R_BDIV] = 0x0000000F;
     s->r[R_TTRIG] = 0x00000020;
+}
+
+static void cadence_uart_reset_hold(Object *obj)
+{
+    CadenceUARTState *s = CADENCE_UART(obj);
 
     uart_rx_reset(s);
     uart_tx_reset(s);
@@ -491,6 +518,14 @@ static void cadence_uart_realize(DeviceState *dev, Error **errp)
                              uart_event, NULL, s, NULL, true);
 }
 
+static void cadence_uart_refclk_update(void *opaque)
+{
+    CadenceUARTState *s = opaque;
+
+    /* recompute uart's speed on clock change */
+    uart_parameters_setup(s);
+}
+
 static void cadence_uart_init(Object *obj)
 {
     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
@@ -500,9 +535,23 @@ static void cadence_uart_init(Object *obj)
     sysbus_init_mmio(sbd, &s->iomem);
     sysbus_init_irq(sbd, &s->irq);
 
+    s->refclk = qdev_init_clock_in(DEVICE(obj), "refclk",
+            cadence_uart_refclk_update, s);
+    /* initialize the frequency in case the clock remains unconnected */
+    clock_set_hz(s->refclk, UART_DEFAULT_REF_CLK);
+
     s->char_tx_time = (NANOSECONDS_PER_SECOND / 9600) * 10;
 }
 
+static int cadence_uart_pre_load(void *opaque)
+{
+    CadenceUARTState *s = opaque;
+
+    /* the frequency will be overriden if the refclk field is present */
+    clock_set_hz(s->refclk, UART_DEFAULT_REF_CLK);
+    return 0;
+}
+
 static int cadence_uart_post_load(void *opaque, int version_id)
 {
     CadenceUARTState *s = opaque;
@@ -521,8 +570,9 @@ static int cadence_uart_post_load(void *opaque, int version_id)
 
 static const VMStateDescription vmstate_cadence_uart = {
     .name = "cadence_uart",
-    .version_id = 2,
+    .version_id = 3,
     .minimum_version_id = 2,
+    .pre_load = cadence_uart_pre_load,
     .post_load = cadence_uart_post_load,
     .fields = (VMStateField[]) {
         VMSTATE_UINT32_ARRAY(r, CadenceUARTState, CADENCE_UART_R_MAX),
@@ -534,8 +584,9 @@ static const VMStateDescription vmstate_cadence_uart = {
         VMSTATE_UINT32(tx_count, CadenceUARTState),
         VMSTATE_UINT32(rx_wpos, CadenceUARTState),
         VMSTATE_TIMER_PTR(fifo_trigger_handle, CadenceUARTState),
+        VMSTATE_CLOCK_V(refclk, CadenceUARTState, 3),
         VMSTATE_END_OF_LIST()
-    }
+    },
 };
 
 static Property cadence_uart_properties[] = {
@@ -546,10 +597,12 @@ static Property cadence_uart_properties[] = {
 static void cadence_uart_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
+    ResettableClass *rc = RESETTABLE_CLASS(klass);
 
     dc->realize = cadence_uart_realize;
     dc->vmsd = &vmstate_cadence_uart;
-    dc->reset = cadence_uart_reset;
+    rc->phases.enter = cadence_uart_reset_init;
+    rc->phases.hold  = cadence_uart_reset_hold;
     device_class_set_props(dc, cadence_uart_properties);
   }
 
diff --git a/hw/char/trace-events b/hw/char/trace-events
index 6f938301d98..d20eafd56f8 100644
--- a/hw/char/trace-events
+++ b/hw/char/trace-events
@@ -97,3 +97,6 @@ exynos_uart_wo_read(uint32_t channel, const char *name, uint32_t reg) "UART%d: T
 exynos_uart_rxsize(uint32_t channel, uint32_t size) "UART%d: Rx FIFO size: %d"
 exynos_uart_channel_error(uint32_t channel) "Wrong UART channel number: %d"
 exynos_uart_rx_timeout(uint32_t channel, uint32_t stat, uint32_t intsp) "UART%d: Rx timeout stat=0x%x intsp=0x%x"
+
+# hw/char/cadence_uart.c
+cadence_uart_baudrate(unsigned baudrate) "baudrate %u"
-- 
2.20.1



  parent reply	other threads:[~2020-04-30 11:58 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-04-30 11:51 [PULL 00/31] target-arm queue Peter Maydell
2020-04-30 11:51 ` [PULL 01/31] dma/xlnx-zdma: Fix descriptor loading (MEM) wrt endianness Peter Maydell
2020-04-30 11:51 ` [PULL 02/31] dma/xlnx-zdma: Fix descriptor loading (REG) " Peter Maydell
2020-04-30 11:51 ` [PULL 03/31] nrf51: Fix last GPIO CNF address Peter Maydell
2020-04-30 11:51 ` [PULL 04/31] bugfix: Use gicr_typer in arm_gicv3_icc_reset Peter Maydell
2020-04-30 11:51 ` [PULL 05/31] Typo: Correct the name of CPU hotplug memory region Peter Maydell
2020-04-30 11:51 ` [PULL 06/31] hw/net: Add Smartfusion2 emac block Peter Maydell
2020-04-30 11:51 ` [PULL 07/31] msf2: Add EMAC block to SmartFusion2 SoC Peter Maydell
2020-04-30 11:51 ` [PULL 08/31] tests/boot_linux_console: Add ethernet test to SmartFusion2 Peter Maydell
2020-04-30 11:51 ` [PULL 09/31] hw/core/clock: introduce clock object Peter Maydell
2020-04-30 14:35   ` Peter Maydell
2020-10-17 11:47   ` Philippe Mathieu-Daudé
2020-10-20 16:06     ` Philippe Mathieu-Daudé
2020-10-20 16:46       ` Peter Maydell
2020-10-20 17:46         ` Philippe Mathieu-Daudé
2020-04-30 11:51 ` [PULL 10/31] hw/core/clock-vmstate: define a vmstate entry for clock state Peter Maydell
2020-04-30 11:51 ` [PULL 11/31] qdev: add clock input&output support to devices Peter Maydell
2020-04-30 11:51 ` [PULL 12/31] qdev-clock: introduce an init array to ease the device construction Peter Maydell
2020-04-30 11:51 ` [PULL 13/31] docs/clocks: add device's clock documentation Peter Maydell
2020-04-30 11:51 ` [PULL 14/31] hw/misc/zynq_slcr: add clock generation for uarts Peter Maydell
2020-04-30 11:51 ` Peter Maydell [this message]
2020-04-30 11:51 ` [PULL 16/31] hw/arm/xilinx_zynq: connect uart clocks to slcr Peter Maydell
2020-04-30 11:51 ` [PULL 17/31] qdev-monitor: print the device's clock with info qtree Peter Maydell
2020-04-30 11:51 ` [PULL 18/31] hw/arm: versal: Setup the ADMA with 128bit bus-width Peter Maydell
2020-04-30 11:51 ` [PULL 19/31] Cadence: gem: fix wraparound in 64bit descriptors Peter Maydell
2020-04-30 11:51 ` [PULL 20/31] net: cadence_gem: clear RX control descriptor Peter Maydell
2020-04-30 11:51 ` [PULL 21/31] target/arm: Vectorize integer comparison vs zero Peter Maydell
2020-04-30 11:51 ` [PULL 22/31] hw/arm/virt: dt: move creation of /secure-chosen to create_fdt() Peter Maydell
2020-04-30 11:51 ` [PULL 23/31] hw/arm/virt: dt: add kaslr-seed property Peter Maydell
2020-04-30 11:51 ` [PULL 24/31] target/arm: Restrict the Address Translate write operation to TCG accel Peter Maydell
2020-04-30 11:51 ` [PULL 25/31] target/arm: Make cpu_register() available for other files Peter Maydell
2020-04-30 11:51 ` [PULL 26/31] target/arm/cpu: Use ARRAY_SIZE() to iterate over ARMCPUInfo[] Peter Maydell
2020-04-30 14:30   ` Peter Maydell
2020-04-30 11:51 ` [PULL 27/31] target/arm/cpu: Update coding style to make checkpatch.pl happy Peter Maydell
2020-04-30 14:52   ` Philippe Mathieu-Daudé
2020-04-30 11:51 ` [PULL 28/31] device_tree: Allow name wildcards in qemu_fdt_node_path() Peter Maydell
2020-04-30 11:51 ` [PULL 29/31] device_tree: Constify compat " Peter Maydell
2020-04-30 11:51 ` [PULL 30/31] hw/arm: xlnx-zcu102: Move arm_boot_info into XlnxZCU102 Peter Maydell
2020-04-30 11:51 ` [PULL 31/31] hw/arm: xlnx-zcu102: Disable unsupported FDT firmware nodes Peter Maydell
2020-05-01  2:05 ` [PULL 00/31] target-arm queue no-reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200430115142.13430-16-peter.maydell@linaro.org \
    --to=peter.maydell@linaro.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).