[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH v8 7/9] hw/char/cadence_uart: add clock support
From: |
Alistair Francis |
Subject: |
Re: [PATCH v8 7/9] hw/char/cadence_uart: add clock support |
Date: |
Wed, 26 Feb 2020 14:54:41 -0800 |
On Tue, Feb 25, 2020 at 5:31 AM Damien Hedde <address@hidden> wrote:
>
> 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 <address@hidden>
Reviewed-by: Alistair Francis <address@hidden>
Alistair
>
> ---
>
> v7:
> + update ClockIn/ClockOut types
> + update due to resettable changes
> + use a versioned field instead subsection in vmstate
> ---
> 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 47cec956c4..2a179a572f 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 22e47972f1..e196906c92 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 6f938301d9..d20eafd56f 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.25.1
>
>
- [PATCH v8 2/9] hw/core/clock-vmstate: define a vmstate entry for clock state, (continued)
- [PATCH v8 2/9] hw/core/clock-vmstate: define a vmstate entry for clock state, Damien Hedde, 2020/02/25
- [PATCH v8 4/9] qdev-clock: introduce an init array to ease the device construction, Damien Hedde, 2020/02/25
- [PATCH v8 3/9] qdev: add clock input&output support to devices., Damien Hedde, 2020/02/25
- [PATCH v8 9/9] qdev-monitor: print the device's clock with info qtree, Damien Hedde, 2020/02/25
- [PATCH v8 6/9] hw/misc/zynq_slcr: add clock generation for uarts, Damien Hedde, 2020/02/25
- [PATCH v8 7/9] hw/char/cadence_uart: add clock support, Damien Hedde, 2020/02/25
- Re: [PATCH v8 7/9] hw/char/cadence_uart: add clock support,
Alistair Francis <=
- [PATCH v8 8/9] hw/arm/xilinx_zynq: connect uart clocks to slcr, Damien Hedde, 2020/02/25
- [PATCH v8 5/9] docs/clocks: add device's clock documentation, Damien Hedde, 2020/02/25