]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
serial: Add Goldfish TTY driver
authorKuan-Wei Chiu <visitorckw@gmail.com>
Wed, 7 Jan 2026 20:18:30 +0000 (20:18 +0000)
committerTom Rini <trini@konsulko.com>
Mon, 2 Feb 2026 20:24:40 +0000 (14:24 -0600)
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 <visitorckw@gmail.com>
Reviewed-by: Yao Zi <me@ziyao.cc>
Tested-by: Daniel Palmer <daniel@0x0f.com>
Acked-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Simon Glass <simon.glass@canonical.com>
Acked-by: Angelo Dureghello <angelo@kernel-space.org>
MAINTAINERS
drivers/serial/Kconfig
drivers/serial/Makefile
drivers/serial/serial_goldfish.c [new file with mode: 0644]
include/goldfish_tty.h [new file with mode: 0644]

index 27ce73d83f4871f87eccf665d3d3e0bcd58ff122..8f884ff495a6a77ae5541b1ba49617b00ec1c2c9 100644 (file)
@@ -1260,6 +1260,12 @@ S:       Maintained
 F:     drivers/misc/gsc.c
 F:     include/gsc.h
 
+GOLDFISH SERIAL DRIVER
+M:     Kuan-Wei Chiu <visitorckw@gmail.com>
+S:     Maintained
+F:     drivers/serial/serial_goldfish.c
+F:     include/goldfish_tty.h
+
 INTERCONNECT:
 M:     Neil Armstrong <neil.armstrong@linaro.org>
 S:     Maintained
index 371d7aa5bbae7525b47d433a71155f6a9dc0f157..b84cb9ec781db429d238704636a4831b5c348c17 100644 (file)
@@ -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
index 8eaae62b0fc4a6cf68ba1a25eeb2442d6bdb577c..fe8d23be5123c11881207baf89f1c949c7a97bdd 100644 (file)
@@ -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 (file)
index 0000000..4ac2cfb
--- /dev/null
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2025, Kuan-Wei Chiu <visitorckw@gmail.com>
+ * 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 (file)
index 0000000..db49c8d
--- /dev/null
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2025, Kuan-Wei Chiu <visitorckw@gmail.com>
+ */
+
+#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_ */