summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKuan-Wei Chiu <[email protected]>2026-01-07 20:18:30 +0000
committerTom Rini <[email protected]>2026-02-02 14:24:40 -0600
commitbf55b84736d6b220dae11e3b1e7a670918d9daee (patch)
tree142992b0560f5aaff416824dad57201565b0b07f
parentf2f69886ac181e74fa378cf49bdee33e6e9a4188 (diff)
serial: Add Goldfish TTY driver
Add support for the Google Goldfish TTY serial device. This virtual device is commonly used in QEMU virtual machines (such as the m68k virt machine) and Android emulators. The driver implements basic console output and input polling using the Goldfish MMIO interface. Signed-off-by: Kuan-Wei Chiu <[email protected]> Reviewed-by: Yao Zi <[email protected]> Tested-by: Daniel Palmer <[email protected]> Acked-by: Heinrich Schuchardt <[email protected]> Reviewed-by: Simon Glass <[email protected]> Acked-by: Angelo Dureghello <[email protected]>
-rw-r--r--MAINTAINERS6
-rw-r--r--drivers/serial/Kconfig8
-rw-r--r--drivers/serial/Makefile1
-rw-r--r--drivers/serial/serial_goldfish.c117
-rw-r--r--include/goldfish_tty.h18
5 files changed, 150 insertions, 0 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 27ce73d83f4..8f884ff495a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1260,6 +1260,12 @@ S: Maintained
F: drivers/misc/gsc.c
F: include/gsc.h
+GOLDFISH SERIAL DRIVER
+M: Kuan-Wei Chiu <[email protected]>
+S: Maintained
+F: drivers/serial/serial_goldfish.c
+F: include/goldfish_tty.h
+
INTERCONNECT:
M: Neil Armstrong <[email protected]>
S: Maintained
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 371d7aa5bba..b84cb9ec781 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -1193,4 +1193,12 @@ config SYS_SDMR
depends on MPC8XX_CONS
default 0x0
+config SERIAL_GOLDFISH
+ bool "Goldfish TTY support"
+ depends on DM_SERIAL
+ help
+ Select this to enable support for the Goldfish TTY serial port.
+ This virtual device is commonly used by QEMU virtual machines
+ (e.g. m68k virt) for console output.
+
endif
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 8eaae62b0fc..fe8d23be512 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -63,3 +63,4 @@ obj-$(CONFIG_XTENSA_SEMIHOSTING_SERIAL) += serial_xtensa_semihosting.o
obj-$(CONFIG_S5P4418_PL011_SERIAL) += serial_s5p4418_pl011.o
obj-$(CONFIG_UART4_SERIAL) += serial_adi_uart4.o
+obj-$(CONFIG_SERIAL_GOLDFISH) += serial_goldfish.o
diff --git a/drivers/serial/serial_goldfish.c b/drivers/serial/serial_goldfish.c
new file mode 100644
index 00000000000..4ac2cfb6231
--- /dev/null
+++ b/drivers/serial/serial_goldfish.c
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2025, Kuan-Wei Chiu <[email protected]>
+ * Goldfish TTY driver for U-Boot
+ */
+
+#include <dm.h>
+#include <goldfish_tty.h>
+#include <mapmem.h>
+#include <serial.h>
+#include <asm/io.h>
+#include <linux/types.h>
+
+/* Goldfish TTY Register Offsets */
+#define GOLDFISH_TTY_PUT_CHAR 0x00
+#define GOLDFISH_TTY_BYTES_READY 0x04
+#define GOLDFISH_TTY_CMD 0x08
+#define GOLDFISH_TTY_DATA_PTR 0x10
+#define GOLDFISH_TTY_DATA_LEN 0x14
+#define GOLDFISH_TTY_DATA_PTR_HIGH 0x18
+#define GOLDFISH_TTY_VERSION 0x20
+
+/* Commands */
+#define CMD_WRITE_BUFFER 2
+#define CMD_READ_BUFFER 3
+
+struct goldfish_tty_priv {
+ void __iomem *base;
+ u8 rx_buf;
+};
+
+static int goldfish_serial_getc(struct udevice *dev)
+{
+ struct goldfish_tty_priv *priv = dev_get_priv(dev);
+ unsigned long paddr;
+ u32 count;
+
+ count = __raw_readl(priv->base + GOLDFISH_TTY_BYTES_READY);
+ if (count == 0)
+ return -EAGAIN;
+
+ paddr = virt_to_phys((void *)&priv->rx_buf);
+
+ __raw_writel(0, priv->base + GOLDFISH_TTY_DATA_PTR_HIGH);
+ __raw_writel(paddr, priv->base + GOLDFISH_TTY_DATA_PTR);
+ __raw_writel(1, priv->base + GOLDFISH_TTY_DATA_LEN);
+ __raw_writel(CMD_READ_BUFFER, priv->base + GOLDFISH_TTY_CMD);
+
+ return priv->rx_buf;
+}
+
+static int goldfish_serial_putc(struct udevice *dev, const char ch)
+{
+ struct goldfish_tty_priv *priv = dev_get_priv(dev);
+
+ __raw_writel(ch, priv->base + GOLDFISH_TTY_PUT_CHAR);
+
+ return 0;
+}
+
+static int goldfish_serial_pending(struct udevice *dev, bool input)
+{
+ struct goldfish_tty_priv *priv = dev_get_priv(dev);
+
+ if (input)
+ return __raw_readl(priv->base + GOLDFISH_TTY_BYTES_READY);
+
+ return 0;
+}
+
+static int goldfish_serial_of_to_plat(struct udevice *dev)
+{
+ struct goldfish_tty_plat *plat = dev_get_plat(dev);
+ fdt_addr_t addr;
+
+ addr = dev_read_addr(dev);
+ if (addr != FDT_ADDR_T_NONE)
+ plat->reg = addr;
+
+ return 0;
+}
+
+static int goldfish_serial_probe(struct udevice *dev)
+{
+ struct goldfish_tty_plat *plat = dev_get_plat(dev);
+ struct goldfish_tty_priv *priv = dev_get_priv(dev);
+
+ if (!plat->reg)
+ return -EINVAL;
+
+ priv->base = map_sysmem(plat->reg, 0x1000);
+
+ return 0;
+}
+
+static const struct dm_serial_ops goldfish_serial_ops = {
+ .putc = goldfish_serial_putc,
+ .pending = goldfish_serial_pending,
+ .getc = goldfish_serial_getc,
+};
+
+static const struct udevice_id goldfish_serial_ids[] = {
+ { .compatible = "google,goldfish-tty" },
+ { }
+};
+
+U_BOOT_DRIVER(serial_goldfish) = {
+ .name = "serial_goldfish",
+ .id = UCLASS_SERIAL,
+ .of_match = goldfish_serial_ids,
+ .of_to_plat = goldfish_serial_of_to_plat,
+ .plat_auto = sizeof(struct goldfish_tty_plat),
+ .probe = goldfish_serial_probe,
+ .ops = &goldfish_serial_ops,
+ .priv_auto = sizeof(struct goldfish_tty_priv),
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/include/goldfish_tty.h b/include/goldfish_tty.h
new file mode 100644
index 00000000000..db49c8d6344
--- /dev/null
+++ b/include/goldfish_tty.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2025, Kuan-Wei Chiu <[email protected]>
+ */
+
+#ifndef _GOLDFISH_TTY_H_
+#define _GOLDFISH_TTY_H_
+
+#include <linux/types.h>
+
+/* Platform data for the Goldfish TTY driver
+ * Used to pass hardware base address from Board to Driver
+ */
+struct goldfish_tty_plat {
+ phys_addr_t reg;
+};
+
+#endif /* _GOLDFISH_TTY_H_ */