[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 1/2] hw/char: Add STM32F7 peripheral: USART
|
From: |
Evgeny Ermakov |
|
Subject: |
[PATCH 1/2] hw/char: Add STM32F7 peripheral: USART |
|
Date: |
Wed, 30 Nov 2022 15:12:58 +1100 |
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