diff mbox series

[v2,06/10] drivers: serial: Add xtensa semihosting driver

Message ID 20240522-qemu-xtensa-v2-6-04bf7e42b10b@flygoat.com
State Changes Requested
Delegated to: Tom Rini
Headers show
Series xtensa: Enable qemu-xtensa board | expand

Commit Message

Jiaxun Yang May 22, 2024, 5:08 p.m. UTC
Add xtensa semihosting driver.

It can't use regular semihosting driver as Xtensa's has it's own
semihosting ABI.

Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
---
v2:
	- Fix simc_serial_pending implementation
	- Get puts work
---
 drivers/serial/Kconfig                     | 18 +++++-
 drivers/serial/Makefile                    |  1 +
 drivers/serial/serial_xtensa_semihosting.c | 92 ++++++++++++++++++++++++++++++
 3 files changed, 110 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 1fe4607598eb..3a1e5a6f2877 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -501,6 +501,15 @@  config DEBUG_UART_MT7620
 	  driver will be available until the real driver model serial is
 	  running.
 
+config DEBUG_UART_XTENSA_SEMIHOSTING
+	bool "Xtensa semihosting"
+	depends on XTENSA_SEMIHOSTING_SERIAL
+	help
+	  Select this to enable the debug UART using the Xtensa semihosting driver.
+	  This provides basic serial output from the console without needing to
+	  start up driver model. The driver will be available until the real
+	  driver model serial is running.
+
 endchoice
 
 config DEBUG_UART_BASE
@@ -936,7 +945,6 @@  config SH_SCIF_CLK_FREQ
 config SEMIHOSTING_SERIAL
 	bool "Semihosting UART support"
 	depends on SEMIHOSTING && !SERIAL_RX_BUFFER
-	imply SERIAL_PUTS
 	help
 	  Select this to enable a serial UART using semihosting. Special halt
 	  instructions will be issued which an external debugger (such as a
@@ -1115,6 +1123,14 @@  config XEN_SERIAL
 	  If built without DM support, then requires Xen
 	  to be built with CONFIG_VERBOSE_DEBUG.
 
+config XTENSA_SEMIHOSTING_SERIAL
+	bool "Xtensa Semihosting UART support"
+	depends on DM_SERIAL
+	depends on XTENSA_SEMIHOSTING
+	imply SERIAL_PUTS
+	help
+	  Select this to enable a serial UART using Xtensa semihosting.
+
 choice
 	prompt "Console port"
 	default 8xx_CONS_SMC1
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index dbe598b74064..78810f98367c 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -60,6 +60,7 @@  obj-$(CONFIG_MT7620_SERIAL) += serial_mt7620.o
 obj-$(CONFIG_HTIF_CONSOLE) += serial_htif.o
 obj-$(CONFIG_SIFIVE_SERIAL) += serial_sifive.o
 obj-$(CONFIG_XEN_SERIAL) += serial_xen.o
+obj-$(CONFIG_XTENSA_SEMIHOSTING_SERIAL) += serial_xtensa_semihosting.o
 obj-$(CONFIG_S5P4418_PL011_SERIAL) += serial_s5p4418_pl011.o
 
 ifndef CONFIG_SPL_BUILD
diff --git a/drivers/serial/serial_xtensa_semihosting.c b/drivers/serial/serial_xtensa_semihosting.c
new file mode 100644
index 000000000000..0e59a9bfdc75
--- /dev/null
+++ b/drivers/serial/serial_xtensa_semihosting.c
@@ -0,0 +1,92 @@ 
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ */
+
+#include <dm.h>
+#include <malloc.h>
+#include <serial.h>
+
+#include <asm/platform/simcall.h>
+
+/**
+ * struct simc_serial_priv - Semihosting serial private data
+ * @counter: Counter used to fake pending every other call
+ */
+struct simc_serial_priv {
+	unsigned int counter;
+};
+
+static int simc_serial_getc(struct udevice *dev)
+{
+	char ch = 0;
+
+	simc_read(0, &ch, sizeof(ch));
+
+	return ch;
+}
+
+static int simc_serial_putc(struct udevice *dev, const char ch)
+{
+	char str[2] = {0};
+
+	str[0] = ch;
+	simc_write(1, str, 1);
+
+	return 0;
+}
+
+static int simc_serial_pending(struct udevice *dev, bool input)
+{
+	struct simc_serial_priv *priv = dev_get_priv(dev);
+
+	if (input) {
+		int res = simc_poll(0);
+		return res < 0 ? priv->counter++ & 1 : res;
+	}
+
+	return false;
+}
+
+static ssize_t smh_serial_puts(struct udevice *dev, const char *s, size_t len)
+{
+	int ret;
+
+	ret = simc_write(1, s, len);
+
+	return ret;
+}
+
+static const struct dm_serial_ops simc_serial_ops = {
+	.putc = simc_serial_putc,
+	.puts = smh_serial_puts,
+	.getc = simc_serial_getc,
+	.pending = simc_serial_pending,
+};
+
+U_BOOT_DRIVER(simc_serial) = {
+	.name	= "serial_xtensa_semihosting",
+	.id	= UCLASS_SERIAL,
+	.priv_auto = sizeof(struct simc_serial_priv),
+	.ops	= &simc_serial_ops,
+	.flags	= DM_FLAG_PRE_RELOC,
+};
+
+U_BOOT_DRVINFO(simc_serial) = {
+	.name = "serial_xtensa_semihosting",
+};
+
+#if CONFIG_IS_ENABLED(DEBUG_UART_XTENSA_SEMIHOSTING)
+#include <debug_uart.h>
+
+static inline void _debug_uart_init(void)
+{
+}
+
+static inline void _debug_uart_putc(int c)
+{
+	simc_serial_putc(NULL, c);
+}
+
+DEBUG_UART_FUNCS
+#endif