All of lore.kernel.org
 help / color / mirror / Atom feed
From: Evgeny Ermakov <evgeny.v.ermakov@gmail.com>
To: qemu-devel@nongnu.org
Cc: Evgeny Ermakov <evgeny.v.ermakov@gmail.com>
Subject: [PATCH 1/2] hw/char: Add STM32F7 peripheral: USART
Date: Wed, 30 Nov 2022 15:12:58 +1100	[thread overview]
Message-ID: <20221130041259.12032-2-evgeny.v.ermakov@gmail.com> (raw)
In-Reply-To: <20221130041259.12032-1-evgeny.v.ermakov@gmail.com>

Signed-off-by: Evgeny Ermakov <evgeny.v.ermakov@gmail.com>
---
 include/hw/char/stm32f7xx_usart.h |  30 +++
 hw/char/stm32f7xx_usart.c         | 361 ++++++++++++++++++++++++++++++
 hw/arm/Kconfig                    |   1 +
 hw/char/Kconfig                   |   3 +
 hw/char/meson.build               |   1 +
 hw/char/trace-events              |   4 +
 6 files changed, 400 insertions(+)
 create mode 100644 include/hw/char/stm32f7xx_usart.h
 create mode 100644 hw/char/stm32f7xx_usart.c

diff --git a/include/hw/char/stm32f7xx_usart.h b/include/hw/char/stm32f7xx_usart.h
new file mode 100644
index 0000000000..ec005be8d8
--- /dev/null
+++ b/include/hw/char/stm32f7xx_usart.h
@@ -0,0 +1,30 @@
+/*
+ * STM32F7XX Universal synchronous/asynchronous receiver transmitter (USART)
+ *
+ * Copyright (c) 2022 Evgeny Ermakov <evgeny.v.ermakov@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HW_CHAR_STM32F7XX_USART_H
+#define HW_CHAR_STM32F7XX_USART_H
+
+#include "hw/arm/stm32f.h"
+#include "chardev/char-fe.h"
+
+#define TYPE_STM32F7XX_USART "stm32f7xx-usart"
+OBJECT_DECLARE_SIMPLE_TYPE(STM32F7XXUSARTState, STM32F7XX_USART)
+
+#define STM32F7XX_USART_R_MAX 11
+
+struct STM32F7XXUSARTState {
+    /*< private >*/
+    STM32FPeripheralState parent_obj;
+
+    uint32_t regs[STM32F7XX_USART_R_MAX];
+
+    CharBackend chr;
+    qemu_irq irq;
+};
+
+#endif /* HW_CHAR_STM32F7XX_USART_H */
diff --git a/hw/char/stm32f7xx_usart.c b/hw/char/stm32f7xx_usart.c
new file mode 100644
index 0000000000..122781705a
--- /dev/null
+++ b/hw/char/stm32f7xx_usart.c
@@ -0,0 +1,361 @@
+/*
+ * STM32F7XX Universal synchronous/asynchronous receiver transmitter (USART)
+ *
+ * Reference documents:
+ *   - Reference manual RM0385
+ *       "STM32F75xxx and stm32f74xxx advanced Arm(R)-based 32-bit MCUs"
+ *   - Reference manual RM0410
+ *       "STM32F76xxx and STM32F77xxx advanced Arm(R)-based 32-bit MCUs"
+ *
+ * Copyright (c) 2022 Evgeny Ermakov <evgeny.v.ermakov@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/char/stm32f7xx_usart.h"
+#include "hw/irq.h"
+#include "hw/qdev-properties-system.h"
+#include "hw/registerfields.h"
+#include "migration/vmstate.h"
+#include "qemu/log.h"
+#include "trace.h"
+
+#ifndef STM_USART_ERR_DEBUG
+#define STM_USART_ERR_DEBUG 0
+#endif
+
+#define DB_PRINT_L(lvl, fmt, args...)                   \
+    do {                                                \
+        if (STM_USART_ERR_DEBUG >= lvl) {               \
+            qemu_log("%s: " fmt, __func__, ## args);    \
+        }                                               \
+    } while (0)
+
+#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args)
+
+REG32(CR1,         0x00)
+    /* reserved: 31:29, 1 */
+    FIELD(CR1,        M1,             28, 1)
+    FIELD(CR1,        EOBIE,          27, 1)
+    FIELD(CR1,        RTOIE,          26, 1)
+    FIELD(CR1,        DEAT,           21, 5)
+    FIELD(CR1,        DEDT,           16, 5)
+    FIELD(CR1,        OVER8,          15, 1)
+    FIELD(CR1,        CMIE,           14, 1)
+    FIELD(CR1,        MME,            13, 1)
+    FIELD(CR1,        M0,             12, 1)
+    FIELD(CR1,        WAKE,           11, 1)
+    FIELD(CR1,        PCE,            10, 1)
+    FIELD(CR1,        PS,              9, 1)
+    FIELD(CR1,        PEIE,            8, 1)
+    FIELD(CR1,        TXEIE,           7, 1)
+    FIELD(CR1,        TCIE,            6, 1)
+    FIELD(CR1,        RXNEIE,          5, 1)
+    FIELD(CR1,        IDLEIE,          4, 1)
+    FIELD(CR1,        TE,              3, 1)
+    FIELD(CR1,        RE,              2, 1)
+    FIELD(CR1,        UE,              0, 1)
+REG32(CR2,         0x04)
+    /* reserved: 7, 3:0 */
+    FIELD(CR2,        ADD,            24, 8)
+    FIELD(CR2,        RTOEN,          23, 1)
+    FIELD(CR2,        ABRMOD,         21, 2)
+    FIELD(CR2,        ABREN,          20, 1)
+    FIELD(CR2,        MSBFIRST,       19, 1)
+    FIELD(CR2,        DATAINV,        18, 1)
+    FIELD(CR2,        TXINV,          17, 1)
+    FIELD(CR2,        RXINV,          16, 1)
+    FIELD(CR2,        SWAP,           15, 1)
+    FIELD(CR2,        LINEN,          14, 1)
+    FIELD(CR2,        STOP,           12, 2)
+    FIELD(CR2,        CLKEN,          11, 1)
+    FIELD(CR2,        CPOL,           10, 1)
+    FIELD(CR2,        CPHA,            9, 1)
+    FIELD(CR2,        LBCL,            8, 1)
+    FIELD(CR2,        LBDIE,           6, 1)
+    FIELD(CR2,        LBDL,            5, 1)
+    FIELD(CR2,        ADDM7,           4, 1)
+REG32(CR3,         0x08)
+    /* reserved: 31:25, 16 */
+    FIELD(CR3,        TCBGTIE,        24, 1)
+    FIELD(CR3,        UCESM,          23, 1)
+    FIELD(CR3,        WUFIE,          22, 1)
+    FIELD(CR3,        WUS,            20, 2)
+    FIELD(CR3,        SCARCNT,        17, 3)
+    FIELD(CR3,        DEP,            15, 1)
+    FIELD(CR3,        DEM,            14, 1)
+    FIELD(CR3,        DDRE,           13, 1)
+    FIELD(CR3,        OVRDIS,         12, 1)
+    FIELD(CR3,        ONEBIT,         11, 1)
+    FIELD(CR3,        CTSIE,          10, 1)
+    FIELD(CR3,        CTSE,            9, 1)
+    FIELD(CR3,        RTSE,            8, 1)
+    FIELD(CR3,        DMAT,            7, 1)
+    FIELD(CR3,        DMAR,            6, 1)
+    FIELD(CR3,        SCEN,            5, 1)
+    FIELD(CR3,        NACK,            4, 1)
+    FIELD(CR3,        HDSEL,           3, 1)
+    FIELD(CR3,        IRLP,            2, 1)
+    FIELD(CR3,        IREN,            1, 1)
+    FIELD(CR3,        EIE,             0, 1)
+REG32(BRR,         0x0c)
+    /* reserved: 31:16 */
+    FIELD(BRR,        BRR,             0, 15)
+REG32(GTPR,        0x10)
+    /* reserved: 31:16 */
+    FIELD(GTPR,       GT,              8, 8)
+    FIELD(GTPR,       PSC,             0, 8)
+REG32(RTOR,        0x14)
+    FIELD(RTOR,       BLEN,           24, 8)
+    FIELD(RTOR,       RTO,             0, 24)
+REG32(RQR,         0x18)
+    /* reserved: 31:5 */
+    FIELD(RQR,        TXFRQ,           4, 1)
+    FIELD(RQR,        RXFRQ,           3, 1)
+    FIELD(RQR,        MMRQ,            2, 1)
+    FIELD(RQR,        SBKRQ,           1, 1)
+    FIELD(RQR,        ABRRQ,           0, 1)
+REG32(ISR,         0x1c)
+    /* reserved: 31:26, 24:23, 13 */
+    FIELD(ISR,        TCBGT,          25, 1)
+    FIELD(ISR,        REACK,          22, 1)
+    FIELD(ISR,        TEACK,          21, 1)
+    FIELD(ISR,        WUF,            20, 1)
+    FIELD(ISR,        RWU,            19, 1)
+    FIELD(ISR,        SBKF,           18, 1)
+    FIELD(ISR,        CMF,            17, 1)
+    FIELD(ISR,        BUSY,           16, 1)
+    FIELD(ISR,        ABRF,           15, 1)
+    FIELD(ISR,        ABRE,           14, 1)
+    FIELD(ISR,        EOBF,           12, 1)
+    FIELD(ISR,        RTOF,           11, 1)
+    FIELD(ISR,        CTS,            10, 1)
+    FIELD(ISR,        CTSIF,           9, 1)
+    FIELD(ISR,        LBDF,            8, 1)
+    FIELD(ISR,        TXE,             7, 1)
+    FIELD(ISR,        TC,              6, 1)
+    FIELD(ISR,        RXNE,            5, 1)
+    FIELD(ISR,        IDLE,            4, 1)
+    FIELD(ISR,        ORE,             3, 1)
+    FIELD(ISR,        NF,              2, 1)
+    FIELD(ISR,        FE,              1, 1)
+    FIELD(ISR,        PE,              0, 1)
+REG32(ICR,         0x20)
+    /* reserved: 31:21, 19:18, 16:13, 10, 5 */
+    FIELD(ICR,        WUCF,           20, 1)
+    FIELD(ICR,        CMCF,           17, 1)
+    FIELD(ICR,        EOBCF,          12, 1)
+    FIELD(ICR,        RTOCF,          11, 1)
+    FIELD(ICR,        CTSCF,           9, 1)
+    FIELD(ICR,        LBDCF,           8, 1)
+    FIELD(ICR,        TCBGTCF,         7, 1)
+    FIELD(ICR,        TCCF,            6, 1)
+    FIELD(ICR,        IDLECF,          4, 1)
+    FIELD(ICR,        ORECF,           3, 1)
+    FIELD(ICR,        NCF,             2, 1)
+    FIELD(ICR,        FECF,            1, 1)
+    FIELD(ICR,        PECF,            0, 1)
+REG32(RDR,         0x24)
+    /* reserved: 31:9 */
+    FIELD(RDR,        RDR,             0, 9)
+REG32(TDR,         0x28)
+    /* reserved: 31:9 */
+    FIELD(TDR,        TDR,             0, 9)
+
+
+static int stm32f7xx_usart_can_receive(void *opaque)
+{
+    /* STM32F7XXUSARTState *s = opaque; */
+
+    /* if (!(s->usart_sr & USART_SR_RXNE)) { */
+    /*     return 1; */
+    /* } */
+
+    return 0;
+}
+
+static void stm32f7xx_usart_receive(void *opaque, const uint8_t *buf, int size)
+{
+#if 0
+    STM32F7XXUSARTState *s = opaque;
+
+    if (!(s->usart_cr1 & USART_CR1_UE && s->usart_cr1 & USART_CR1_RE)) {
+        /* USART not enabled - drop the chars */
+        DB_PRINT("Dropping the chars\n");
+        return;
+    }
+
+    s->usart_dr = *buf;
+    s->usart_sr |= USART_SR_RXNE;
+
+    if (s->usart_cr1 & USART_CR1_RXNEIE) {
+        qemu_set_irq(s->irq, 1);
+    }
+
+    DB_PRINT("Receiving: %c\n", s->usart_dr);
+#endif
+}
+
+static uint32_t stm32f7xx_usart_read(void *opaque, hwaddr addr,
+                                     unsigned int size)
+{
+    STM32F7XXUSARTState *s = opaque;
+
+    trace_stm32f7xx_usart_read(addr);
+
+    switch (addr) {
+    case A_CR1:
+        return s->regs[R_CR1];
+    case A_CR2:
+        return s->regs[R_CR2];
+    case A_CR3:
+        return s->regs[R_CR3];
+    case A_BRR:
+        return s->regs[R_BRR];
+    case A_GTPR:
+        return s->regs[R_GTPR];
+    case A_RTOR:
+        return s->regs[R_RTOR];
+    case A_RQR:
+        return s->regs[R_RQR];
+    case A_ISR:
+        return s->regs[R_ISR];
+    case A_ICR:
+        return s->regs[R_ICR];
+    case A_RDR:
+        return s->regs[R_RDR];
+    case A_TDR:
+        return s->regs[R_TDR];
+    default:
+        STM32F_LOG_BAD_OFFSET();
+        break;
+    }
+
+    return 0;
+}
+
+static void stm32f7xx_usart_write(void *opaque, hwaddr addr,
+                                  uint32_t value, unsigned int size)
+{
+    STM32F7XXUSARTState *s = opaque;
+    /* unsigned char ch; */
+
+    trace_stm32f7xx_usart_write(addr, value);
+
+    switch (addr) {
+    case A_CR1:
+        s->regs[R_CR1] = value;
+        break;
+    case A_CR2:
+        s->regs[R_CR2] = value;
+        break;
+    case A_CR3:
+        s->regs[R_CR3] = value;
+        break;
+    case A_BRR:
+        s->regs[R_BRR] = value;
+        break;
+    case A_GTPR:
+        s->regs[R_GTPR] = value;
+        break;
+    case A_RTOR:
+        s->regs[R_RTOR] = value;
+        break;
+    case A_RQR:
+        s->regs[R_RQR] = value;
+        break;
+    case A_ISR:
+        s->regs[R_ISR] = value;
+        break;
+    case A_ICR:
+        s->regs[R_ICR] = value;
+        break;
+    case A_RDR:
+        s->regs[R_RDR] = value;
+        break;
+    case A_TDR:
+        if (value < 0xf000) {
+            uint8_t ch = value;
+            /* XXX this blocks entire thread. Rewrite to use
+             * qemu_chr_fe_write and background I/O callbacks */
+            qemu_chr_fe_write_all(&s->chr, &ch, 1);
+            /* XXX I/O are currently synchronous, making it impossible for
+               software to observe transient states where TXE or TC aren't
+               set. Unlike TXE however, which is read-only, software may
+               clear TC by writing 0 to the SR register, so set it again
+               on each write. */
+            /* s->usart_sr |= USART_SR_TC; */
+        }
+        break;
+    default:
+        STM32F_LOG_BAD_OFFSET();
+        break;
+    }
+}
+
+static void stm32f7xx_usart_reset_enter(Object *obj, ResetType type)
+{
+    STM32F7XXUSARTState *s = STM32F7XX_USART(obj);
+
+    memset(s->regs, 0, sizeof(s->regs));
+    s->regs[R_ISR] = 0x020000c0;
+}
+
+static void stm32f7xx_usart_reset_exit(Object *obj)
+{
+    STM32F7XXUSARTState *s = STM32F7XX_USART(obj);
+
+    qemu_set_irq(s->irq, 0);
+}
+
+static void stm32f7xx_usart_init(Object *obj)
+{
+    STM32F7XXUSARTState *s = STM32F7XX_USART(obj);
+
+    sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
+}
+
+static void stm32f7xx_usart_realize(DeviceState *dev, Error **errp)
+{
+    STM32F7XXUSARTState *s = STM32F7XX_USART(dev);
+
+    qemu_chr_fe_set_handlers(&s->chr, stm32f7xx_usart_can_receive,
+                             stm32f7xx_usart_receive, NULL, NULL,
+                             s, NULL, true);
+}
+
+static Property stm32f7xx_usart_properties[] = {
+    DEFINE_PROP_CHR("chardev", STM32F7XXUSARTState, chr),
+    DEFINE_PROP_END_OF_LIST()
+};
+
+static void stm32f7xx_usart_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    STM32FPeripheralClass *pc = STM32F_PERIPHERAL_CLASS(klass);
+    ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+    dc->realize = stm32f7xx_usart_realize;
+    device_class_set_props(dc, stm32f7xx_usart_properties);
+    rc->phases.enter = stm32f7xx_usart_reset_enter;
+    rc->phases.exit = stm32f7xx_usart_reset_exit;
+    pc->mmio_size = 0x400;
+    pc->mmio_read = stm32f7xx_usart_read;
+    pc->mmio_write = stm32f7xx_usart_write;
+}
+
+static const TypeInfo stm32f7xx_usart_info = {
+    .name          = TYPE_STM32F7XX_USART,
+    .parent        = TYPE_STM32F_PERIPHERAL,
+    .instance_size = sizeof(STM32F7XXUSARTState),
+    .instance_init = stm32f7xx_usart_init,
+    .class_init    = stm32f7xx_usart_class_init,
+};
+
+static void stm32f7xx_usart_register_types(void)
+{
+    type_register_static(&stm32f7xx_usart_info);
+}
+
+type_init(stm32f7xx_usart_register_types)
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index c2f6e748b0..02dfbcb99a 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -376,6 +376,7 @@ config STM32F405_SOC
 config STM32F7XX_SOC
     bool
     select STM32F
+    select STM32F7XX_USART
 
 config XLNX_ZYNQMP_ARM
     bool
diff --git a/hw/char/Kconfig b/hw/char/Kconfig
index 6b6cf2fc1d..22b1cf8062 100644
--- a/hw/char/Kconfig
+++ b/hw/char/Kconfig
@@ -41,6 +41,9 @@ config VIRTIO_SERIAL
 config STM32F2XX_USART
     bool
 
+config STM32F7XX_USART
+    bool
+
 config CMSDK_APB_UART
     bool
 
diff --git a/hw/char/meson.build b/hw/char/meson.build
index 7b594f51b8..6230750375 100644
--- a/hw/char/meson.build
+++ b/hw/char/meson.build
@@ -31,6 +31,7 @@ softmmu_ss.add(when: 'CONFIG_RENESAS_SCI', if_true: files('renesas_sci.c'))
 softmmu_ss.add(when: 'CONFIG_SIFIVE_UART', if_true: files('sifive_uart.c'))
 softmmu_ss.add(when: 'CONFIG_SH_SCI', if_true: files('sh_serial.c'))
 softmmu_ss.add(when: 'CONFIG_STM32F2XX_USART', if_true: files('stm32f2xx_usart.c'))
+softmmu_ss.add(when: 'CONFIG_STM32F7XX_USART', if_true: files('stm32f7xx_usart.c'))
 softmmu_ss.add(when: 'CONFIG_MCHP_PFSOC_MMUART', if_true: files('mchp_pfsoc_mmuart.c'))
 
 specific_ss.add(when: 'CONFIG_HTIF', if_true: files('riscv_htif.c'))
diff --git a/hw/char/trace-events b/hw/char/trace-events
index 2ecb36232e..41fa3c0b46 100644
--- a/hw/char/trace-events
+++ b/hw/char/trace-events
@@ -105,3 +105,7 @@ cadence_uart_baudrate(unsigned baudrate) "baudrate %u"
 # sh_serial.c
 sh_serial_read(char *id, unsigned size, uint64_t offs, uint64_t val) " %s size %d offs 0x%02" PRIx64 " -> 0x%02" PRIx64
 sh_serial_write(char *id, unsigned size, uint64_t offs, uint64_t val) "%s size %d offs 0x%02" PRIx64 " <- 0x%02" PRIx64
+
+# stm32f7xx_usart.c
+stm32f7xx_usart_read(uint64_t addr) " addr: 0x%02" PRIx64
+stm32f7xx_usart_write(uint64_t addr, uint64_t data) "addr: 0x%02" PRIx64 " val: 0x%" PRIx64
-- 
2.38.1



  reply	other threads:[~2022-11-30  4:14 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-11-30  4:12 [PATCH 0/2] Implement something Evgeny Ermakov
2022-11-30  4:12 ` Evgeny Ermakov [this message]
2022-11-30  4:12 ` [PATCH 2/2] hw/input: Add FT5336 touch controller Evgeny Ermakov
2022-11-30  4:17 ` [PATCH 0/2] Implement something Evgeny Ermakov

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=20221130041259.12032-2-evgeny.v.ermakov@gmail.com \
    --to=evgeny.v.ermakov@gmail.com \
    --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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.